{"openapi":"3.1.0","info":{"title":"Dynex Public API","version":"3.1.0","description":"A DynexV3 publikus API-ja. Hitelesítés: `Authorization: Bearer dxp_…` tokennel, amit a vezérlőpulton hozol létre (Beállítások → API integrációk). A korábbi `dxk_` kulcsok is elfogadottak. Hibák: `{ error: { code, message, details? } }`. Alap sebességkorlát: 120 kérés/perc/token. FIGYELEM: a kivezetés alatt álló végpontok NEM a dokumentum-szintű szerveren élnek, hanem a saját, művelet-szintű `servers` bejegyzésükön (`/api/v1`). Ezek `deprecated: true` jelölést viselnek, és a hibaválaszuk borítéka `{ success: false, error: { code, message } }`."},"servers":[{"url":"https://prod.dynex.hu/api/v3"}],"tags":[{"name":"me"},{"name":"reservations"},{"name":"availability"},{"name":"contacts"},{"name":"pipelines"},{"name":"deals"},{"name":"orders"},{"name":"menu"},{"name":"loyalty"},{"name":"reviews"},{"name":"webhooks"},{"name":"conversions"},{"name":"content"},{"name":"blog"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"dxp_<token>"}},"schemas":{},"parameters":{}},"paths":{"/me":{"get":{"operationId":"me.get","tags":["me"],"summary":"Token adatainak lekérdezése","description":"Az integráció első hívása szokott lenni: megmondja, kihez tartozik a kulcs, mit szabad vele, mikor jár le, és hozzávetőleg mennyi maradt a percalapú keretből (a `rateLimit.remaining` tájékoztató érték, lásd a mező leírását). Scope nem kell hozzá, tehát bármely érvényes kulcs hívhatja - ezért alkalmas a kulcs beállításának ellenőrzésére is. Ha ez `401`-et ad, a kulcs hibás, lejárt vagy visszavont; ha `403`-at, maga a kulcs rendben van, de a fiók vagy a hívó IP-címe zárja ki a hívást; ha `200`-at, de a `scopes` üres, a kulcs nem kapott jogosultságot.\n\nBármely érvényes token hívhatja.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Sikeres válasz","content":{"application/json":{"schema":{"type":"object","properties":{"tokenId":{"type":"string","description":"A használt API-kulcs azonosítója. Naplózáshoz és hibabejelentéshez ezt add meg - magát a kulcsot soha ne."},"label":{"type":"string","description":"A kulcshoz a Beállítások oldalon adott név. Ebből derül ki, melyik integráció kulcsával hívsz."},"tenantId":{"type":"string","description":"Annak a fióknak az azonosítója, amelyhez a kulcs tartozik. Minden hívás automatikusan erre a fiókra szűkül, külön fiókazonosítót nem kell küldeni."},"scopes":{"type":"array","items":{"type":"string"},"description":"A kulcshoz rendelt jogosultságok. Egy végpont akkor hívható, ha a `scope` mezőjében megadott érték ebben a listában szerepel, vagy ha a lista tartalmazza a `*` értéket. A `scope` nélküli (`null`) végpontok - például ez a `/me` - bármely érvényes kulccsal hívhatók."},"expiresAt":{"type":["string","null"],"format":"date-time","description":"A kulcs lejáratának időpontja UTC-ben. `null`, ha a kulcs nem jár le. A korábbi rendszerből származó, `dxk_` előtagú kulcsoknál mindig `null`."},"rateLimit":{"type":"object","properties":{"perMinute":{"type":"integer","description":"A kulcsra beállított percenkénti kérés-keret. Ezt tekintsd a saját ütemezésed felső határának. A számlálás kiszolgáló-példányonként történik, ezért a rendszer alkalmanként ennél többet is átengedhet - erre építeni viszont nem szabad."},"remaining":{"type":"integer","description":"Hány hívás maradt a keretből annál a kiszolgáló-példánynál, amelyik ezt a hívást kiszolgálta; ez a hívás már le van vonva belőle. Az ablak nem naptári perchez igazodik: az ablak első hívásától számított 60 másodperc múlva áll vissza teljesre a keret. Tájékoztató érték: a következő hívásod másik példányra futhat, és ott magasabb - frissen indult példányon `perMinute - 1` - értéket látsz. Ütemezést ne erre építs, hanem a `perMinute` betartására és a `429` válasz `Retry-After` fejlécére."}},"required":["perMinute","remaining"]}},"required":["tokenId","label","tenantId","scopes","expiresAt","rateLimit"]}}}},"401":{"description":"unauthorized: Hiányzó, hibás formátumú, ismeretlen, visszavont vagy lejárt token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"403":{"description":"forbidden: A token nem rendelkezik a szükséges scope-pal, a hívó IP nincs a kulcs allowlistáján, a fiók csomagja nem tartalmaz API-hozzáférést, vagy a fiók írás-tiltott (bemutató mód).","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"429":{"description":"rate_limited: A percalapú sebességkorlát (alapból 120 kérés/perc/kulcs) túllépve.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"500":{"description":"internal_error: Váratlan szerverhiba. Egyetlen végponton (`POST /contacts`) ugyanez a hiba a rövidebb `internal` kóddal érkezik - kezeld a kettőt azonosan.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}}}}},"/reservations/{id}/cancel":{"post":{"operationId":"reservations.cancel","tags":["reservations"],"summary":"Foglalás lemondása (vendéglátó oldalról)","description":"A foglalást `cancelled` állapotba teszi a hely nevében, lefuttatja az elutasítás-automatizmust (értesítés a vendégnek, kapacitás felszabadítása), és kiküldi a `reservation.cancelled` webhookot. A törzs elhagyható: törzs nélkül is hívható, a `reason` mezővel viszont saját lemondási ok adható meg. Már lemondott foglalásra a válasz `200`, de a hívás ilyenkor nem csinál semmit: nem fut le újra az automatizmus, és webhook sem megy ki.\n\nSzükséges scope: `reservations.manage`.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Erőforrás-azonosító"},"required":true,"description":"Erőforrás-azonosító","name":"id","in":"path"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"reason":{"type":"string","maxLength":500,"description":"A lemondás oka, szabad szöveg. Elhagyható; ha nincs megadva vagy üres, a rendszer a rögzített `Étterem lemondta` szöveget menti. Ez a szöveg kerül a foglalás `cancelReason` mezőjébe, a `reservation.cancelled` webhookba, és a vendégnek kiküldött lemondó levél `{{decline_reason}}` változójába is - tehát a vendég is elolvassa. Legfeljebb 500 karakter, a körülvevő szóközöket a rendszer levágja."}}}}}},"responses":{"200":{"description":"Sikeres válasz","content":{"application/json":{"schema":{"type":"object","properties":{"reservation":{"type":"object","properties":{"id":{"type":"string","description":"A foglalás állandó azonosítója. Ezt add át az `/reservations/{id}` alatti végpontoknak."},"date":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$","description":"A foglalás napja a vendéglátóhely helyi idejében."},"startTime":{"type":"string","pattern":"^([01]\\d|2[0-3]):[0-5]\\d$","description":"Az érkezés időpontja helyi idő szerint."},"endTime":{"type":"string","pattern":"^([01]\\d|2[0-3]):[0-5]\\d$","description":"A foglalás tervezett vége helyi idő szerint; az asztal ennyi ideig van lekötve. A rendszer az érkezési időponthoz adja hozzá a hely foglalási hosszát, amit a létszám növelhet (nagyobb társaság tovább marad). A nyitvatartás ebbe nem számít bele: a végidő túlnyúlhat a záráson, és éjfél után záró helynél át is fordulhat a következő naptári napra - ilyenkor kisebb, mint a `startTime` (például 23:30 + 120 perc = `01:30`), miközben a `date` a szolgáltatási napot mutatja. Időtartam-számításnál ezért: ha az `endTime` nem nagyobb a `startTime`-nál, egy napot hozzá kell adni."},"partySize":{"type":"integer","description":"A vendégek száma, gyerekekkel együtt."},"status":{"type":"string","enum":["pending","pending_payment","confirmed","seated","completed","cancelled","no_show","walk_in"],"description":"A foglalás aktuális állapota. Az átmeneteket a `/reservations/{id}/status` és a `/reservations/{id}/cancel` végpont vezérli."},"source":{"type":"string","description":"Honnan érkezett a foglalás. Az API-n keresztül létrehozottak mindig `api` értéket kapnak, a saját online foglalási űrlapunkról érkezők `online`-t, az átemelt vagy importált foglalások `third_party`-t. További előforduló értékek: `phone`, `walk_in`, `email`, `app`. A mező szabad szöveg, nem zárt felsorolás: régi vagy importált sor ezeken kívüli értéket is hordozhat, ezért ismeretlen forrásra is fel kell készülni."},"type":{"type":"string","description":"`reservation` egy hétköznapi asztalfoglalásnál, `event` egy rendezvénynél. A rendezvényeknek van `title`-jük."},"title":{"type":["string","null"],"description":"A rendezvény neve. Csak `type=event` esetén van kitöltve, egyébként `null`."},"customerName":{"type":"string","description":"A foglaló neve, ahogy megadta. Mindig jelen van a válaszban, de lehet ÜRES string: az oszlop alapértéke üres, és a nem az API-n keresztül létrejött foglalásoknál (importált sorok, a felületen név nélkül rögzített foglalás) így is maradhat. Megjelenítéshez vagy kulcsképzéshez számíts az üres értékre."},"customerPhone":{"type":"string","description":"A foglaló telefonszáma, ahogy megadta. Nincs egységesítve, tehát nem feltétlenül E.164 alakú. Az oszlop alapértéke üres string, ezért ez a mező is lehet üres."},"customerEmail":{"type":["string","null"],"description":"A foglaló e-mail címe, ha megadta. Nincs formátum-ellenőrizve."},"contactId":{"type":["string","null"],"description":"Annak a CRM-kontaktnak az azonosítója, amelyhez a foglalás tartozik. A `POST /reservations` mindig kapcsol kontaktot: e-mail cím vagy telefonszám alapján megkeresi a meglévőt, vagy újat hoz létre - a saját felületeinken felvett foglalás is így viselkedik. `null` csak olyan sornál fordul elő, amelyhez nem sikerült kontaktot rendelni (például kézzel vagy importból rögzített régebbi foglalás). A kontakt részleteit a `GET /contacts/{id}` adja."},"notes":{"type":["string","null"],"description":"A vendég szabad szöveges megjegyzése a foglaláshoz."},"specialRequests":{"type":["string","null"],"description":"Külön kérés (például allergia, ünnepi alkalom, ültetési igény), ha a felvevő felület gyűjti."},"customFieldValues":{"type":["object","null"],"additionalProperties":{"type":"string"},"description":"A foglalási űrlap egyedi mezőinek értékei, mezőazonosító szerint. Minden érték string."},"deposit":{"type":["object","null"],"properties":{"amount":{"type":"number","description":"Az előleg fizetendő összege forintban. Százalékos típusnál ez a már kiszámított összeg, ne számold újra."},"type":{"type":"string","enum":["fixed","percentage"],"description":"`fixed`: a hely által beállított rögzített forintösszeg. `percentage`: százalékos előleg, amelynek alapja NEM a fogyasztás vagy a rendelés értéke, hanem egy fejenkénti, rendszerszintű 5000 Ft-os becsült érték - a fizetendő összeg `kerekítés(létszám * 5000 * százalék / 100)`."},"status":{"type":"string","enum":["pending","paid","refunded","forfeited"],"description":"`pending`: még nem fizették be. `paid`: beérkezett. `refunded`: visszatérítve. `forfeited`: a vendég elbukta (például meg nem jelenés miatt)."}},"required":["amount","type","status"],"description":"Az előleg adatai, ha a foglaláshoz tartozik. `null`, ha a hely nem kér előleget ehhez a foglaláshoz. Az előleg fizetési határideje az API-n keresztül nem kérdezhető le, csak a fenti három mező érhető el."},"confirmedAt":{"type":["string","null"],"format":"date-time","description":"A visszaigazolás időpontja UTC-ben. `null`, amíg a foglalás nem került `confirmed` állapotba."},"cancelledAt":{"type":["string","null"],"format":"date-time","description":"A lemondás időpontja UTC-ben. `null`, ha a foglalás nincs lemondva."},"cancelReason":{"type":["string","null"],"description":"A lemondás oka. A `POST /reservations/{id}/cancel` a törzsben küldött `reason` mezőt menti ide; ha nem küldesz okot, a rögzített `Étterem lemondta` szöveget, mert a hívást a rendszer a hely nevében végzi. Ha a vendég mondta le a saját kezelőlinkjéről, `Vendég lemondta (online)` szerepel itt. Előfordulnak egyéb, nem API-eredetű értékek is: a munkatárs által a kezelőfelületen beírt szabad szöveg, a telefonos lemondás címkéje, vagy átvett adatoknál a törlés jelölése. A mező tehát ember által olvasható, magyar nyelvű címke, NEM zárt felsorolás - programozott elágazást ne erre építs. `null`, ha a foglalás nincs lemondva, vagy ha a felületen ok megadása nélkül mondták le."},"createdAt":{"type":"string","format":"date-time","description":"A foglalás létrejöttének időpontja UTC-ben."},"updatedAt":{"type":"string","format":"date-time","description":"Az utolsó módosítás időpontja UTC-ben. Ezt a mezőt szűri az `updatedSince` query-paraméter szinkronizáláshoz."}},"required":["id","date","startTime","endTime","partySize","status","source","type","title","customerName","customerPhone","customerEmail","contactId","notes","specialRequests","customFieldValues","deposit","confirmedAt","cancelledAt","cancelReason","createdAt","updatedAt"]},"cancelled":{"type":"boolean","enum":[true],"description":"Mindig `true`. Azért van a válaszban, hogy a hívó a törzsből is lássa a sikert, ne csak a státuszkódból. Egy már korábban lemondott foglalásnál is `true`, tehát nem jelzi, hogy ez a hívás változtatott-e bármit."}},"required":["reservation","cancelled"]}}}},"400":{"description":"invalid_request: A séma-validáció bukott, vagy hiányzik egy kötelező paraméter. A `details[]` mezőnként sorolja fel az okot.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"401":{"description":"unauthorized: Hiányzó, hibás formátumú, ismeretlen, visszavont vagy lejárt token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"403":{"description":"forbidden: A token nem rendelkezik a szükséges scope-pal, a hívó IP nincs a kulcs allowlistáján, a fiók csomagja nem tartalmaz API-hozzáférést, vagy a fiók írás-tiltott (bemutató mód).","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"404":{"description":"not_found: Az erőforrás nem létezik EBBEN a fiókban. Egy másik fiókhoz tartozó azonosító is ezt adja - a kettő szándékosan megkülönböztethetetlen.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"422":{"description":"reservation_rejected: Szintaktikailag helyes foglalás-kérés, amit egy üzleti szabály utasít el: nincs szabad asztal az adott időpontra, a hely zárva van, a dátum a múltban van, vagy a foglalás jelenlegi állapotából nem vezet út a kért állapotba (például egy már lemondott foglalás leültetése).","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"429":{"description":"rate_limited: A percalapú sebességkorlát (alapból 120 kérés/perc/kulcs) túllépve.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"500":{"description":"internal_error: Váratlan szerverhiba. Egyetlen végponton (`POST /contacts`) ugyanez a hiba a rövidebb `internal` kóddal érkezik - kezeld a kettőt azonosan.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}}}}},"/reservations":{"post":{"operationId":"reservations.create","tags":["reservations"],"summary":"Foglalás létrehozása","description":"Új foglalást vesz fel a vendég nevében, és a hely saját szabályai szerint azonnal vissza is igazolhatja. A kérés végigmegy ugyanazon a kapacitás- és nyitvatartás-ellenőrzésen, mint a saját foglalási felületünk: ha nincs szabad hely az adott időpontban, `422` a válasz, nem `400`. A hívás idempotens: `Idempotency-Key` fejléccel a hálózati újrapróbálkozás nem hoz létre második foglalást; ezen felül fejléc nélkül is fut egy rövid duplikátum-védelem, lásd a figyelmeztetéseket. FIGYELEM: a végpont nem csak egy foglalás-sort ír. A megadott e-mail cím vagy telefonszám alapján CRM-kontaktot is keres, és találat hiányában ÚJAT hoz létre; meglévő kontaktnál a nevet, az egyedi mezőket és a jegyzetet kiegészíti, a marketing hozzájárulást pedig felminősítheti. A kontakton nő a foglalásszámláló, aktivitás-bejegyzés készül, és a fiókban beállított küszöb felett a kontakt automatikusan VIP címkét és státuszt kap. A vendég adatkezelési hozzájárulásának beszerzéséért és bizonyításáért az integrátor felel - lásd a figyelmeztetéseket.\n\nSzükséges scope: `reservations.write`.\n\nTámogatja az `Idempotency-Key` fejlécet.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"date":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$","description":"A foglalás napja a hely helyi idejében. Múltbeli nap elutasításra kerül."},"startTime":{"type":"string","pattern":"^([01]\\d|2[0-3]):[0-5]\\d$","description":"Az érkezés időpontja helyi idő szerint. A végét a rendszer számolja, nem kell megadni."},"partySize":{"type":"integer","minimum":1,"maximum":1000,"description":"A vendégek száma. Az 1-1000 tartományon kívüli érték `400`-at ad, ez azonban csak formai korlát: a ténylegesen elfogadott létszámsávot a hely beállítása szabja meg, és az azon kívül eső - egyébként 1-1000 közötti - létszám `422 reservation_rejected` választ kap. Lásd a figyelmeztetéseket."},"customerName":{"type":"string","minLength":1,"description":"A foglaló neve. A szélső szóközök levágódnak; a csak szóközből álló érték üresnek számít, tehát elutasításra kerül."},"customerPhone":{"type":"string","minLength":1,"description":"A foglaló telefonszáma. Formátum-ellenőrzés nincs, a megadott alak úgy tárolódik, ahogy küldted - ezért érdemes nemzetközi (`+36...`) alakban küldeni. Ez a mező kulcsa a rövid duplikátum-védelemnek is, lásd a figyelmeztetéseket."},"customerEmail":{"description":"A foglaló e-mail címe. Formátum-ellenőrzés nincs. Nem string típusú érték nem okoz hibát: a mező ilyenkor egyszerűen üresen marad."},"notes":{"description":"A vendég szabad szöveges megjegyzése. Hosszkorlát nincs. Nem string típusú érték itt sem okoz hibát, csak üresen marad a mező. A hely beállíthatja, hogy a megjegyzéssel érkező foglalás kézi jóváhagyásra várjon."},"customFieldValues":{"type":"object","additionalProperties":{"type":"string"},"description":"A foglalási űrlap egyedi mezőinek értékei, mezőazonosító szerint. Minden értéknek stringnek kell lennie: egyetlen szám vagy logikai érték is `400`-at ad az egész kérésre. Az értékek a foglaláshoz kapcsolt CRM-kontaktra is felkerülnek."},"marketingConsent":{"type":"boolean","description":"Marketing hozzájárulás a vendégtől. Csak a szigorúan `true` érték állítja be; minden más érték figyelmen kívül marad, és nem is hibázik."}},"required":["date","startTime","partySize","customerName","customerPhone"]}}}},"responses":{"201":{"description":"Sikeres válasz","content":{"application/json":{"schema":{"type":"object","properties":{"reservation":{"type":"object","properties":{"id":{"type":"string","description":"A foglalás állandó azonosítója. Ezt add át az `/reservations/{id}` alatti végpontoknak."},"date":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$","description":"A foglalás napja a vendéglátóhely helyi idejében."},"startTime":{"type":"string","pattern":"^([01]\\d|2[0-3]):[0-5]\\d$","description":"Az érkezés időpontja helyi idő szerint."},"endTime":{"type":"string","pattern":"^([01]\\d|2[0-3]):[0-5]\\d$","description":"A foglalás tervezett vége helyi idő szerint; az asztal ennyi ideig van lekötve. A rendszer az érkezési időponthoz adja hozzá a hely foglalási hosszát, amit a létszám növelhet (nagyobb társaság tovább marad). A nyitvatartás ebbe nem számít bele: a végidő túlnyúlhat a záráson, és éjfél után záró helynél át is fordulhat a következő naptári napra - ilyenkor kisebb, mint a `startTime` (például 23:30 + 120 perc = `01:30`), miközben a `date` a szolgáltatási napot mutatja. Időtartam-számításnál ezért: ha az `endTime` nem nagyobb a `startTime`-nál, egy napot hozzá kell adni."},"partySize":{"type":"integer","description":"A vendégek száma, gyerekekkel együtt."},"status":{"type":"string","enum":["pending","pending_payment","confirmed","seated","completed","cancelled","no_show","walk_in"],"description":"A foglalás aktuális állapota. Az átmeneteket a `/reservations/{id}/status` és a `/reservations/{id}/cancel` végpont vezérli."},"source":{"type":"string","description":"Honnan érkezett a foglalás. Az API-n keresztül létrehozottak mindig `api` értéket kapnak, a saját online foglalási űrlapunkról érkezők `online`-t, az átemelt vagy importált foglalások `third_party`-t. További előforduló értékek: `phone`, `walk_in`, `email`, `app`. A mező szabad szöveg, nem zárt felsorolás: régi vagy importált sor ezeken kívüli értéket is hordozhat, ezért ismeretlen forrásra is fel kell készülni."},"type":{"type":"string","description":"`reservation` egy hétköznapi asztalfoglalásnál, `event` egy rendezvénynél. A rendezvényeknek van `title`-jük."},"title":{"type":["string","null"],"description":"A rendezvény neve. Csak `type=event` esetén van kitöltve, egyébként `null`."},"customerName":{"type":"string","description":"A foglaló neve, ahogy megadta. Mindig jelen van a válaszban, de lehet ÜRES string: az oszlop alapértéke üres, és a nem az API-n keresztül létrejött foglalásoknál (importált sorok, a felületen név nélkül rögzített foglalás) így is maradhat. Megjelenítéshez vagy kulcsképzéshez számíts az üres értékre."},"customerPhone":{"type":"string","description":"A foglaló telefonszáma, ahogy megadta. Nincs egységesítve, tehát nem feltétlenül E.164 alakú. Az oszlop alapértéke üres string, ezért ez a mező is lehet üres."},"customerEmail":{"type":["string","null"],"description":"A foglaló e-mail címe, ha megadta. Nincs formátum-ellenőrizve."},"contactId":{"type":["string","null"],"description":"Annak a CRM-kontaktnak az azonosítója, amelyhez a foglalás tartozik. A `POST /reservations` mindig kapcsol kontaktot: e-mail cím vagy telefonszám alapján megkeresi a meglévőt, vagy újat hoz létre - a saját felületeinken felvett foglalás is így viselkedik. `null` csak olyan sornál fordul elő, amelyhez nem sikerült kontaktot rendelni (például kézzel vagy importból rögzített régebbi foglalás). A kontakt részleteit a `GET /contacts/{id}` adja."},"notes":{"type":["string","null"],"description":"A vendég szabad szöveges megjegyzése a foglaláshoz."},"specialRequests":{"type":["string","null"],"description":"Külön kérés (például allergia, ünnepi alkalom, ültetési igény), ha a felvevő felület gyűjti."},"customFieldValues":{"type":["object","null"],"additionalProperties":{"type":"string"},"description":"A foglalási űrlap egyedi mezőinek értékei, mezőazonosító szerint. Minden érték string."},"deposit":{"type":["object","null"],"properties":{"amount":{"type":"number","description":"Az előleg fizetendő összege forintban. Százalékos típusnál ez a már kiszámított összeg, ne számold újra."},"type":{"type":"string","enum":["fixed","percentage"],"description":"`fixed`: a hely által beállított rögzített forintösszeg. `percentage`: százalékos előleg, amelynek alapja NEM a fogyasztás vagy a rendelés értéke, hanem egy fejenkénti, rendszerszintű 5000 Ft-os becsült érték - a fizetendő összeg `kerekítés(létszám * 5000 * százalék / 100)`."},"status":{"type":"string","enum":["pending","paid","refunded","forfeited"],"description":"`pending`: még nem fizették be. `paid`: beérkezett. `refunded`: visszatérítve. `forfeited`: a vendég elbukta (például meg nem jelenés miatt)."}},"required":["amount","type","status"],"description":"Az előleg adatai, ha a foglaláshoz tartozik. `null`, ha a hely nem kér előleget ehhez a foglaláshoz. Az előleg fizetési határideje az API-n keresztül nem kérdezhető le, csak a fenti három mező érhető el."},"confirmedAt":{"type":["string","null"],"format":"date-time","description":"A visszaigazolás időpontja UTC-ben. `null`, amíg a foglalás nem került `confirmed` állapotba."},"cancelledAt":{"type":["string","null"],"format":"date-time","description":"A lemondás időpontja UTC-ben. `null`, ha a foglalás nincs lemondva."},"cancelReason":{"type":["string","null"],"description":"A lemondás oka. A `POST /reservations/{id}/cancel` a törzsben küldött `reason` mezőt menti ide; ha nem küldesz okot, a rögzített `Étterem lemondta` szöveget, mert a hívást a rendszer a hely nevében végzi. Ha a vendég mondta le a saját kezelőlinkjéről, `Vendég lemondta (online)` szerepel itt. Előfordulnak egyéb, nem API-eredetű értékek is: a munkatárs által a kezelőfelületen beírt szabad szöveg, a telefonos lemondás címkéje, vagy átvett adatoknál a törlés jelölése. A mező tehát ember által olvasható, magyar nyelvű címke, NEM zárt felsorolás - programozott elágazást ne erre építs. `null`, ha a foglalás nincs lemondva, vagy ha a felületen ok megadása nélkül mondták le."},"createdAt":{"type":"string","format":"date-time","description":"A foglalás létrejöttének időpontja UTC-ben."},"updatedAt":{"type":"string","format":"date-time","description":"Az utolsó módosítás időpontja UTC-ben. Ezt a mezőt szűri az `updatedSince` query-paraméter szinkronizáláshoz."}},"required":["id","date","startTime","endTime","partySize","status","source","type","title","customerName","customerPhone","customerEmail","contactId","notes","specialRequests","customFieldValues","deposit","confirmedAt","cancelledAt","cancelReason","createdAt","updatedAt"]},"reference":{"type":"string","description":"A vendégnek szóló rövid foglalásazonosító. Ezzel keres a `GET /reservations?reference=` szűrő, és ez szerepel a visszaigazoló üzenetben is. Nem egyedi kulcs, lásd a listázó végpont figyelmeztetéseit."},"status":{"type":"string","enum":["pending","pending_payment","confirmed","seated","completed","cancelled","no_show","walk_in"],"description":"A foglalás induló állapota. `confirmed`, ha a hely automatikusan visszaigazol; `pending`, ha kézi jóváhagyás kell. `pending_payment` frissen létrehozott foglalásnál itt nem keletkezik: online előlegfizetést csak a saját foglalási felületünk indít, ezért fizetési hivatkozás sem jön vissza. Kivétel az ismételt hívás védelme: ha a válasz egy korábbi, máshol indított foglalást ad vissza, annak aktuális állapota szerepel itt."},"manageUrl":{"type":"string","description":"Nyilvános hivatkozás, amin a vendég maga módosíthatja vagy lemondhatja a foglalást. Ezt küldd tovább neki."}},"required":["reservation","reference","status","manageUrl"]}}}},"400":{"description":"invalid_request: A séma-validáció bukott, vagy hiányzik egy kötelező paraméter. A `details[]` mezőnként sorolja fel az okot.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"401":{"description":"unauthorized: Hiányzó, hibás formátumú, ismeretlen, visszavont vagy lejárt token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"403":{"description":"forbidden: A token nem rendelkezik a szükséges scope-pal, a hívó IP nincs a kulcs allowlistáján, a fiók csomagja nem tartalmaz API-hozzáférést, vagy a fiók írás-tiltott (bemutató mód).","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"422":{"description":"reservation_rejected: Szintaktikailag helyes foglalás-kérés, amit egy üzleti szabály utasít el: nincs szabad asztal az adott időpontra, a hely zárva van, a dátum a múltban van, vagy a foglalás jelenlegi állapotából nem vezet út a kért állapotba (például egy már lemondott foglalás leültetése).","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"429":{"description":"rate_limited: A percalapú sebességkorlát (alapból 120 kérés/perc/kulcs) túllépve.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"500":{"description":"internal_error: Váratlan szerverhiba. Egyetlen végponton (`POST /contacts`) ugyanez a hiba a rövidebb `internal` kóddal érkezik - kezeld a kettőt azonosan.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}}}},"get":{"operationId":"reservations.list","tags":["reservations"],"summary":"Foglalások listázása","description":"A szűrők ÉS kapcsolattal érvényesülnek. A `reference` megadása foglalásazonosító szerinti keresésre vált. Az `updatedSince` szinkron-lekérdezéshez való: `updatedAt` szerint növekvő sorrendet ad.\n\nSzükséges scope: `reservations.readonly`.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$","description":"Csak az ezen a napon vagy utána kezdődő foglalások. A nap beleszámít."},"required":false,"description":"Csak az ezen a napon vagy utána kezdődő foglalások. A nap beleszámít.","name":"dateFrom","in":"query"},{"schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$","description":"Csak az ezen a napon vagy előtte kezdődő foglalások. A nap beleszámít."},"required":false,"description":"Csak az ezen a napon vagy előtte kezdődő foglalások. A nap beleszámít.","name":"dateTo","in":"query"},{"schema":{"type":"string","enum":["pending","confirmed","seated","completed","cancelled","no_show"],"description":"Szűrés állapotra. Csak az itt felsorolt hat érték fogadható el; a `pending_payment` és a `walk_in` a válaszban előfordulhat, szűrni viszont nem lehet rájuk."},"required":false,"description":"Szűrés állapotra. Csak az itt felsorolt hat érték fogadható el; a `pending_payment` és a `walk_in` a válaszban előfordulhat, szűrni viszont nem lehet rájuk.","name":"status","in":"query"},{"schema":{"type":"string","description":"Egyezés a foglaló e-mail címére. Az összehasonlítás kisbetű-érzéketlen, egyébként szó szerinti."},"required":false,"description":"Egyezés a foglaló e-mail címére. Az összehasonlítás kisbetű-érzéketlen, egyébként szó szerinti.","name":"email","in":"query"},{"schema":{"type":"string","description":"Egyezés a foglaló telefonszámára. Az összehasonlítás előtt MINDEN szóköz kiesik a megadott értékből és a tárolt számból is, tehát a `+36 30 123 4567` alakban rögzült szám `+36301234567`-tel is megtalálható. Más írásjel viszont nem tűnik el: a kötőjel, a zárójel és a `+` szó szerint kell egyezzen, és a `+36...` meg a `06...` kezdet külön értéknek számít."},"required":false,"description":"Egyezés a foglaló telefonszámára. Az összehasonlítás előtt MINDEN szóköz kiesik a megadott értékből és a tárolt számból is, tehát a `+36 30 123 4567` alakban rögzült szám `+36301234567`-tel is megtalálható. Más írásjel viszont nem tűnik el: a kötőjel, a zárójel és a `+` szó szerint kell egyezzen, és a `+36...` meg a `06...` kezdet külön értéknek számít.","name":"phone","in":"query"},{"schema":{"type":"string","description":"Foglalásazonosító (a visszaigazolóban szereplő rövid kód). Megadásakor a többi szűrő nem érvényesül. A kód a foglalás azonosítójának rövidítése, nem egyedi kulcs, ezért ritkán két foglaláshoz is ugyanaz tartozhat - ilyenkor a válasz több elemet ad vissza. Ne vedd automatikusan az első találatot: ha a `reservations` tömb egynél több elemet tartalmaz, egyértelműsítsd a foglalást (például e-mail cím, telefonszám vagy dátum alapján)."},"required":false,"description":"Foglalásazonosító (a visszaigazolóban szereplő rövid kód). Megadásakor a többi szűrő nem érvényesül. A kód a foglalás azonosítójának rövidítése, nem egyedi kulcs, ezért ritkán két foglaláshoz is ugyanaz tartozhat - ilyenkor a válasz több elemet ad vissza. Ne vedd automatikusan az első találatot: ha a `reservations` tömb egynél több elemet tartalmaz, egyértelműsítsd a foglalást (például e-mail cím, telefonszám vagy dátum alapján).","name":"reference","in":"query"},{"schema":{"type":"string","description":"Csak az ezóta módosult foglalások, `updatedAt` szerint növekvő sorrendben. Szinkronizáláshoz: tedd el a legutolsó kapott `updatedAt` értéket, és azt add vissza a következő körben."},"required":false,"description":"Csak az ezóta módosult foglalások, `updatedAt` szerint növekvő sorrendben. Szinkronizáláshoz: tedd el a legutolsó kapott `updatedAt` értéket, és azt add vissza a következő körben.","name":"updatedSince","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":200,"default":50,"description":"Találatok maximális száma (1-200, alapértelmezés 50; a tartományon kívüli érték a határra szorítódik, nem hibát ad)"},"required":false,"description":"Találatok maximális száma (1-200, alapértelmezés 50; a tartományon kívüli érték a határra szorítódik, nem hibát ad)","name":"limit","in":"query"},{"schema":{"type":"integer","minimum":0,"maximum":1000000,"default":0,"description":"Hány találatot ugorjon át (a tartományon kívüli érték a határra szorítódik, nem hibát ad)"},"required":false,"description":"Hány találatot ugorjon át (a tartományon kívüli érték a határra szorítódik, nem hibát ad)","name":"offset","in":"query"}],"responses":{"200":{"description":"Sikeres válasz","content":{"application/json":{"schema":{"type":"object","properties":{"reservations":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"A foglalás állandó azonosítója. Ezt add át az `/reservations/{id}` alatti végpontoknak."},"date":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$","description":"A foglalás napja a vendéglátóhely helyi idejében."},"startTime":{"type":"string","pattern":"^([01]\\d|2[0-3]):[0-5]\\d$","description":"Az érkezés időpontja helyi idő szerint."},"endTime":{"type":"string","pattern":"^([01]\\d|2[0-3]):[0-5]\\d$","description":"A foglalás tervezett vége helyi idő szerint; az asztal ennyi ideig van lekötve. A rendszer az érkezési időponthoz adja hozzá a hely foglalási hosszát, amit a létszám növelhet (nagyobb társaság tovább marad). A nyitvatartás ebbe nem számít bele: a végidő túlnyúlhat a záráson, és éjfél után záró helynél át is fordulhat a következő naptári napra - ilyenkor kisebb, mint a `startTime` (például 23:30 + 120 perc = `01:30`), miközben a `date` a szolgáltatási napot mutatja. Időtartam-számításnál ezért: ha az `endTime` nem nagyobb a `startTime`-nál, egy napot hozzá kell adni."},"partySize":{"type":"integer","description":"A vendégek száma, gyerekekkel együtt."},"status":{"type":"string","enum":["pending","pending_payment","confirmed","seated","completed","cancelled","no_show","walk_in"],"description":"A foglalás aktuális állapota. Az átmeneteket a `/reservations/{id}/status` és a `/reservations/{id}/cancel` végpont vezérli."},"source":{"type":"string","description":"Honnan érkezett a foglalás. Az API-n keresztül létrehozottak mindig `api` értéket kapnak, a saját online foglalási űrlapunkról érkezők `online`-t, az átemelt vagy importált foglalások `third_party`-t. További előforduló értékek: `phone`, `walk_in`, `email`, `app`. A mező szabad szöveg, nem zárt felsorolás: régi vagy importált sor ezeken kívüli értéket is hordozhat, ezért ismeretlen forrásra is fel kell készülni."},"type":{"type":"string","description":"`reservation` egy hétköznapi asztalfoglalásnál, `event` egy rendezvénynél. A rendezvényeknek van `title`-jük."},"title":{"type":["string","null"],"description":"A rendezvény neve. Csak `type=event` esetén van kitöltve, egyébként `null`."},"customerName":{"type":"string","description":"A foglaló neve, ahogy megadta. Mindig jelen van a válaszban, de lehet ÜRES string: az oszlop alapértéke üres, és a nem az API-n keresztül létrejött foglalásoknál (importált sorok, a felületen név nélkül rögzített foglalás) így is maradhat. Megjelenítéshez vagy kulcsképzéshez számíts az üres értékre."},"customerPhone":{"type":"string","description":"A foglaló telefonszáma, ahogy megadta. Nincs egységesítve, tehát nem feltétlenül E.164 alakú. Az oszlop alapértéke üres string, ezért ez a mező is lehet üres."},"customerEmail":{"type":["string","null"],"description":"A foglaló e-mail címe, ha megadta. Nincs formátum-ellenőrizve."},"contactId":{"type":["string","null"],"description":"Annak a CRM-kontaktnak az azonosítója, amelyhez a foglalás tartozik. A `POST /reservations` mindig kapcsol kontaktot: e-mail cím vagy telefonszám alapján megkeresi a meglévőt, vagy újat hoz létre - a saját felületeinken felvett foglalás is így viselkedik. `null` csak olyan sornál fordul elő, amelyhez nem sikerült kontaktot rendelni (például kézzel vagy importból rögzített régebbi foglalás). A kontakt részleteit a `GET /contacts/{id}` adja."},"notes":{"type":["string","null"],"description":"A vendég szabad szöveges megjegyzése a foglaláshoz."},"specialRequests":{"type":["string","null"],"description":"Külön kérés (például allergia, ünnepi alkalom, ültetési igény), ha a felvevő felület gyűjti."},"customFieldValues":{"type":["object","null"],"additionalProperties":{"type":"string"},"description":"A foglalási űrlap egyedi mezőinek értékei, mezőazonosító szerint. Minden érték string."},"deposit":{"type":["object","null"],"properties":{"amount":{"type":"number","description":"Az előleg fizetendő összege forintban. Százalékos típusnál ez a már kiszámított összeg, ne számold újra."},"type":{"type":"string","enum":["fixed","percentage"],"description":"`fixed`: a hely által beállított rögzített forintösszeg. `percentage`: százalékos előleg, amelynek alapja NEM a fogyasztás vagy a rendelés értéke, hanem egy fejenkénti, rendszerszintű 5000 Ft-os becsült érték - a fizetendő összeg `kerekítés(létszám * 5000 * százalék / 100)`."},"status":{"type":"string","enum":["pending","paid","refunded","forfeited"],"description":"`pending`: még nem fizették be. `paid`: beérkezett. `refunded`: visszatérítve. `forfeited`: a vendég elbukta (például meg nem jelenés miatt)."}},"required":["amount","type","status"],"description":"Az előleg adatai, ha a foglaláshoz tartozik. `null`, ha a hely nem kér előleget ehhez a foglaláshoz. Az előleg fizetési határideje az API-n keresztül nem kérdezhető le, csak a fenti három mező érhető el."},"confirmedAt":{"type":["string","null"],"format":"date-time","description":"A visszaigazolás időpontja UTC-ben. `null`, amíg a foglalás nem került `confirmed` állapotba."},"cancelledAt":{"type":["string","null"],"format":"date-time","description":"A lemondás időpontja UTC-ben. `null`, ha a foglalás nincs lemondva."},"cancelReason":{"type":["string","null"],"description":"A lemondás oka. A `POST /reservations/{id}/cancel` a törzsben küldött `reason` mezőt menti ide; ha nem küldesz okot, a rögzített `Étterem lemondta` szöveget, mert a hívást a rendszer a hely nevében végzi. Ha a vendég mondta le a saját kezelőlinkjéről, `Vendég lemondta (online)` szerepel itt. Előfordulnak egyéb, nem API-eredetű értékek is: a munkatárs által a kezelőfelületen beírt szabad szöveg, a telefonos lemondás címkéje, vagy átvett adatoknál a törlés jelölése. A mező tehát ember által olvasható, magyar nyelvű címke, NEM zárt felsorolás - programozott elágazást ne erre építs. `null`, ha a foglalás nincs lemondva, vagy ha a felületen ok megadása nélkül mondták le."},"createdAt":{"type":"string","format":"date-time","description":"A foglalás létrejöttének időpontja UTC-ben."},"updatedAt":{"type":"string","format":"date-time","description":"Az utolsó módosítás időpontja UTC-ben. Ezt a mezőt szűri az `updatedSince` query-paraméter szinkronizáláshoz."}},"required":["id","date","startTime","endTime","partySize","status","source","type","title","customerName","customerPhone","customerEmail","contactId","notes","specialRequests","customFieldValues","deposit","confirmedAt","cancelledAt","cancelReason","createdAt","updatedAt"]},"description":"A találatok az aktuális lapon. Ha `updatedSince`-t adtál meg, `updatedAt` szerint növekvő, egyébként naptári sorrend: `date`, azon belül `startTime` szerint növekvő."},"limit":{"type":"integer","description":"A ténylegesen alkalmazott lapméret. Ha a kérésben nagyobb értéket adtál meg a megengedettnél, itt a maximum jelenik meg."},"offset":{"type":"integer","description":"Az alkalmazott eltolás. A következő laphoz add hozzá a `limit` értékét."}},"required":["reservations","limit","offset"]}}}},"400":{"description":"invalid_request: A séma-validáció bukott, vagy hiányzik egy kötelező paraméter. A `details[]` mezőnként sorolja fel az okot.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"401":{"description":"unauthorized: Hiányzó, hibás formátumú, ismeretlen, visszavont vagy lejárt token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"403":{"description":"forbidden: A token nem rendelkezik a szükséges scope-pal, a hívó IP nincs a kulcs allowlistáján, a fiók csomagja nem tartalmaz API-hozzáférést, vagy a fiók írás-tiltott (bemutató mód).","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"429":{"description":"rate_limited: A percalapú sebességkorlát (alapból 120 kérés/perc/kulcs) túllépve.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"500":{"description":"internal_error: Váratlan szerverhiba. Egyetlen végponton (`POST /contacts`) ugyanez a hiba a rövidebb `internal` kóddal érkezik - kezeld a kettőt azonosan.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}}}}},"/reservations/{id}":{"get":{"operationId":"reservations.get","tags":["reservations"],"summary":"Egy foglalás lekérdezése","description":"Egyetlen foglalás aktuális állapota azonosító alapján. A hívás mindig a friss adatot adja vissza, tehát alkalmas a webhook-értesítés utáni megerősítésre is. Más fiókhoz tartozó azonosítóra `404` a válasz, nem `403` - az API nem árulja el, hogy az azonosító létezik-e máshol.\n\nSzükséges scope: `reservations.readonly`.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Erőforrás-azonosító"},"required":true,"description":"Erőforrás-azonosító","name":"id","in":"path"}],"responses":{"200":{"description":"Sikeres válasz","content":{"application/json":{"schema":{"type":"object","properties":{"reservation":{"type":"object","properties":{"id":{"type":"string","description":"A foglalás állandó azonosítója. Ezt add át az `/reservations/{id}` alatti végpontoknak."},"date":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$","description":"A foglalás napja a vendéglátóhely helyi idejében."},"startTime":{"type":"string","pattern":"^([01]\\d|2[0-3]):[0-5]\\d$","description":"Az érkezés időpontja helyi idő szerint."},"endTime":{"type":"string","pattern":"^([01]\\d|2[0-3]):[0-5]\\d$","description":"A foglalás tervezett vége helyi idő szerint; az asztal ennyi ideig van lekötve. A rendszer az érkezési időponthoz adja hozzá a hely foglalási hosszát, amit a létszám növelhet (nagyobb társaság tovább marad). A nyitvatartás ebbe nem számít bele: a végidő túlnyúlhat a záráson, és éjfél után záró helynél át is fordulhat a következő naptári napra - ilyenkor kisebb, mint a `startTime` (például 23:30 + 120 perc = `01:30`), miközben a `date` a szolgáltatási napot mutatja. Időtartam-számításnál ezért: ha az `endTime` nem nagyobb a `startTime`-nál, egy napot hozzá kell adni."},"partySize":{"type":"integer","description":"A vendégek száma, gyerekekkel együtt."},"status":{"type":"string","enum":["pending","pending_payment","confirmed","seated","completed","cancelled","no_show","walk_in"],"description":"A foglalás aktuális állapota. Az átmeneteket a `/reservations/{id}/status` és a `/reservations/{id}/cancel` végpont vezérli."},"source":{"type":"string","description":"Honnan érkezett a foglalás. Az API-n keresztül létrehozottak mindig `api` értéket kapnak, a saját online foglalási űrlapunkról érkezők `online`-t, az átemelt vagy importált foglalások `third_party`-t. További előforduló értékek: `phone`, `walk_in`, `email`, `app`. A mező szabad szöveg, nem zárt felsorolás: régi vagy importált sor ezeken kívüli értéket is hordozhat, ezért ismeretlen forrásra is fel kell készülni."},"type":{"type":"string","description":"`reservation` egy hétköznapi asztalfoglalásnál, `event` egy rendezvénynél. A rendezvényeknek van `title`-jük."},"title":{"type":["string","null"],"description":"A rendezvény neve. Csak `type=event` esetén van kitöltve, egyébként `null`."},"customerName":{"type":"string","description":"A foglaló neve, ahogy megadta. Mindig jelen van a válaszban, de lehet ÜRES string: az oszlop alapértéke üres, és a nem az API-n keresztül létrejött foglalásoknál (importált sorok, a felületen név nélkül rögzített foglalás) így is maradhat. Megjelenítéshez vagy kulcsképzéshez számíts az üres értékre."},"customerPhone":{"type":"string","description":"A foglaló telefonszáma, ahogy megadta. Nincs egységesítve, tehát nem feltétlenül E.164 alakú. Az oszlop alapértéke üres string, ezért ez a mező is lehet üres."},"customerEmail":{"type":["string","null"],"description":"A foglaló e-mail címe, ha megadta. Nincs formátum-ellenőrizve."},"contactId":{"type":["string","null"],"description":"Annak a CRM-kontaktnak az azonosítója, amelyhez a foglalás tartozik. A `POST /reservations` mindig kapcsol kontaktot: e-mail cím vagy telefonszám alapján megkeresi a meglévőt, vagy újat hoz létre - a saját felületeinken felvett foglalás is így viselkedik. `null` csak olyan sornál fordul elő, amelyhez nem sikerült kontaktot rendelni (például kézzel vagy importból rögzített régebbi foglalás). A kontakt részleteit a `GET /contacts/{id}` adja."},"notes":{"type":["string","null"],"description":"A vendég szabad szöveges megjegyzése a foglaláshoz."},"specialRequests":{"type":["string","null"],"description":"Külön kérés (például allergia, ünnepi alkalom, ültetési igény), ha a felvevő felület gyűjti."},"customFieldValues":{"type":["object","null"],"additionalProperties":{"type":"string"},"description":"A foglalási űrlap egyedi mezőinek értékei, mezőazonosító szerint. Minden érték string."},"deposit":{"type":["object","null"],"properties":{"amount":{"type":"number","description":"Az előleg fizetendő összege forintban. Százalékos típusnál ez a már kiszámított összeg, ne számold újra."},"type":{"type":"string","enum":["fixed","percentage"],"description":"`fixed`: a hely által beállított rögzített forintösszeg. `percentage`: százalékos előleg, amelynek alapja NEM a fogyasztás vagy a rendelés értéke, hanem egy fejenkénti, rendszerszintű 5000 Ft-os becsült érték - a fizetendő összeg `kerekítés(létszám * 5000 * százalék / 100)`."},"status":{"type":"string","enum":["pending","paid","refunded","forfeited"],"description":"`pending`: még nem fizették be. `paid`: beérkezett. `refunded`: visszatérítve. `forfeited`: a vendég elbukta (például meg nem jelenés miatt)."}},"required":["amount","type","status"],"description":"Az előleg adatai, ha a foglaláshoz tartozik. `null`, ha a hely nem kér előleget ehhez a foglaláshoz. Az előleg fizetési határideje az API-n keresztül nem kérdezhető le, csak a fenti három mező érhető el."},"confirmedAt":{"type":["string","null"],"format":"date-time","description":"A visszaigazolás időpontja UTC-ben. `null`, amíg a foglalás nem került `confirmed` állapotba."},"cancelledAt":{"type":["string","null"],"format":"date-time","description":"A lemondás időpontja UTC-ben. `null`, ha a foglalás nincs lemondva."},"cancelReason":{"type":["string","null"],"description":"A lemondás oka. A `POST /reservations/{id}/cancel` a törzsben küldött `reason` mezőt menti ide; ha nem küldesz okot, a rögzített `Étterem lemondta` szöveget, mert a hívást a rendszer a hely nevében végzi. Ha a vendég mondta le a saját kezelőlinkjéről, `Vendég lemondta (online)` szerepel itt. Előfordulnak egyéb, nem API-eredetű értékek is: a munkatárs által a kezelőfelületen beírt szabad szöveg, a telefonos lemondás címkéje, vagy átvett adatoknál a törlés jelölése. A mező tehát ember által olvasható, magyar nyelvű címke, NEM zárt felsorolás - programozott elágazást ne erre építs. `null`, ha a foglalás nincs lemondva, vagy ha a felületen ok megadása nélkül mondták le."},"createdAt":{"type":"string","format":"date-time","description":"A foglalás létrejöttének időpontja UTC-ben."},"updatedAt":{"type":"string","format":"date-time","description":"Az utolsó módosítás időpontja UTC-ben. Ezt a mezőt szűri az `updatedSince` query-paraméter szinkronizáláshoz."}},"required":["id","date","startTime","endTime","partySize","status","source","type","title","customerName","customerPhone","customerEmail","contactId","notes","specialRequests","customFieldValues","deposit","confirmedAt","cancelledAt","cancelReason","createdAt","updatedAt"]}},"required":["reservation"]}}}},"401":{"description":"unauthorized: Hiányzó, hibás formátumú, ismeretlen, visszavont vagy lejárt token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"403":{"description":"forbidden: A token nem rendelkezik a szükséges scope-pal, a hívó IP nincs a kulcs allowlistáján, a fiók csomagja nem tartalmaz API-hozzáférést, vagy a fiók írás-tiltott (bemutató mód).","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"404":{"description":"not_found: Az erőforrás nem létezik EBBEN a fiókban. Egy másik fiókhoz tartozó azonosító is ezt adja - a kettő szándékosan megkülönböztethetetlen.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"429":{"description":"rate_limited: A percalapú sebességkorlát (alapból 120 kérés/perc/kulcs) túllépve.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"500":{"description":"internal_error: Váratlan szerverhiba. Egyetlen végponton (`POST /contacts`) ugyanez a hiba a rövidebb `internal` kóddal érkezik - kezeld a kettőt azonosan.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}}}}},"/reservations/{id}/modify":{"post":{"operationId":"reservations.modify","tags":["reservations"],"summary":"Foglalás módosítása (dátum, időpont, létszám)","description":"Részleges törzs - legalább egy mezőt meg kell adni. Csak `pending` és `confirmed` foglalás módosítható. A szabad kapacitás újra ellenőrzésre kerül, majd kimegy a `reservation.updated` webhook. Ha az új időpontra nincs hely, a válasz `422`, és a foglalás VÁLTOZATLAN marad. A LÉTSZÁM módosítása az előleget is újraszámolja, és ezzel a foglalás `status` és `deposit` mezőjét is átírhatja - a részleteket lásd a figyelmeztetéseknél. Ha a törzs SÉMAILAG érvénytelen (rossz típus, ismeretlen enum-érték) ÉS az `{id}` sem létezik, a válasz `400`, nem `404` - a séma-ellenőrzés megelőzi a létezés-vizsgálatot, hogy egy formailag hibás kérés hívója se kapjon jelzést az erőforrás létezéséről. A sémailag ÉRVÉNYES, de üres `{}` törzs viszont átmegy a séma-ellenőrzésen, ezért ott a létezés-vizsgálat fut előbb: nem létező azonosítóra `404` a válasz, és csak létező erőforrásnál kapod meg a `400`-at.\n\nSzükséges scope: `reservations.manage`.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Erőforrás-azonosító"},"required":true,"description":"Erőforrás-azonosító","name":"id","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"date":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$","description":"Az új nap. Kihagyva a foglalás napja marad."},"startTime":{"type":"string","pattern":"^([01]\\d|2[0-3]):[0-5]\\d$","description":"Az új érkezési időpont. Kihagyva az eredeti időpont marad."},"partySize":{"type":"integer","minimum":1,"maximum":1000,"description":"Az új létszám. Kihagyva az eredeti létszám marad. Ugyanaz a hely-oldali létszámkorlát érvényes, mint a foglalás létrehozásakor: a hely sávján kívüli létszám `422 reservation_rejected`, és a foglalás változatlan marad. FIGYELEM: a létszám módosítása újraszámolja az előleget, és ezzel a foglalás `status` mezőjét is átírhatja - lásd a figyelmeztetéseket."}}}}}},"responses":{"200":{"description":"Sikeres válasz","content":{"application/json":{"schema":{"type":"object","properties":{"reservation":{"type":"object","properties":{"id":{"type":"string","description":"A foglalás állandó azonosítója. Ezt add át az `/reservations/{id}` alatti végpontoknak."},"date":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$","description":"A foglalás napja a vendéglátóhely helyi idejében."},"startTime":{"type":"string","pattern":"^([01]\\d|2[0-3]):[0-5]\\d$","description":"Az érkezés időpontja helyi idő szerint."},"endTime":{"type":"string","pattern":"^([01]\\d|2[0-3]):[0-5]\\d$","description":"A foglalás tervezett vége helyi idő szerint; az asztal ennyi ideig van lekötve. A rendszer az érkezési időponthoz adja hozzá a hely foglalási hosszát, amit a létszám növelhet (nagyobb társaság tovább marad). A nyitvatartás ebbe nem számít bele: a végidő túlnyúlhat a záráson, és éjfél után záró helynél át is fordulhat a következő naptári napra - ilyenkor kisebb, mint a `startTime` (például 23:30 + 120 perc = `01:30`), miközben a `date` a szolgáltatási napot mutatja. Időtartam-számításnál ezért: ha az `endTime` nem nagyobb a `startTime`-nál, egy napot hozzá kell adni."},"partySize":{"type":"integer","description":"A vendégek száma, gyerekekkel együtt."},"status":{"type":"string","enum":["pending","pending_payment","confirmed","seated","completed","cancelled","no_show","walk_in"],"description":"A foglalás aktuális állapota. Az átmeneteket a `/reservations/{id}/status` és a `/reservations/{id}/cancel` végpont vezérli."},"source":{"type":"string","description":"Honnan érkezett a foglalás. Az API-n keresztül létrehozottak mindig `api` értéket kapnak, a saját online foglalási űrlapunkról érkezők `online`-t, az átemelt vagy importált foglalások `third_party`-t. További előforduló értékek: `phone`, `walk_in`, `email`, `app`. A mező szabad szöveg, nem zárt felsorolás: régi vagy importált sor ezeken kívüli értéket is hordozhat, ezért ismeretlen forrásra is fel kell készülni."},"type":{"type":"string","description":"`reservation` egy hétköznapi asztalfoglalásnál, `event` egy rendezvénynél. A rendezvényeknek van `title`-jük."},"title":{"type":["string","null"],"description":"A rendezvény neve. Csak `type=event` esetén van kitöltve, egyébként `null`."},"customerName":{"type":"string","description":"A foglaló neve, ahogy megadta. Mindig jelen van a válaszban, de lehet ÜRES string: az oszlop alapértéke üres, és a nem az API-n keresztül létrejött foglalásoknál (importált sorok, a felületen név nélkül rögzített foglalás) így is maradhat. Megjelenítéshez vagy kulcsképzéshez számíts az üres értékre."},"customerPhone":{"type":"string","description":"A foglaló telefonszáma, ahogy megadta. Nincs egységesítve, tehát nem feltétlenül E.164 alakú. Az oszlop alapértéke üres string, ezért ez a mező is lehet üres."},"customerEmail":{"type":["string","null"],"description":"A foglaló e-mail címe, ha megadta. Nincs formátum-ellenőrizve."},"contactId":{"type":["string","null"],"description":"Annak a CRM-kontaktnak az azonosítója, amelyhez a foglalás tartozik. A `POST /reservations` mindig kapcsol kontaktot: e-mail cím vagy telefonszám alapján megkeresi a meglévőt, vagy újat hoz létre - a saját felületeinken felvett foglalás is így viselkedik. `null` csak olyan sornál fordul elő, amelyhez nem sikerült kontaktot rendelni (például kézzel vagy importból rögzített régebbi foglalás). A kontakt részleteit a `GET /contacts/{id}` adja."},"notes":{"type":["string","null"],"description":"A vendég szabad szöveges megjegyzése a foglaláshoz."},"specialRequests":{"type":["string","null"],"description":"Külön kérés (például allergia, ünnepi alkalom, ültetési igény), ha a felvevő felület gyűjti."},"customFieldValues":{"type":["object","null"],"additionalProperties":{"type":"string"},"description":"A foglalási űrlap egyedi mezőinek értékei, mezőazonosító szerint. Minden érték string."},"deposit":{"type":["object","null"],"properties":{"amount":{"type":"number","description":"Az előleg fizetendő összege forintban. Százalékos típusnál ez a már kiszámított összeg, ne számold újra."},"type":{"type":"string","enum":["fixed","percentage"],"description":"`fixed`: a hely által beállított rögzített forintösszeg. `percentage`: százalékos előleg, amelynek alapja NEM a fogyasztás vagy a rendelés értéke, hanem egy fejenkénti, rendszerszintű 5000 Ft-os becsült érték - a fizetendő összeg `kerekítés(létszám * 5000 * százalék / 100)`."},"status":{"type":"string","enum":["pending","paid","refunded","forfeited"],"description":"`pending`: még nem fizették be. `paid`: beérkezett. `refunded`: visszatérítve. `forfeited`: a vendég elbukta (például meg nem jelenés miatt)."}},"required":["amount","type","status"],"description":"Az előleg adatai, ha a foglaláshoz tartozik. `null`, ha a hely nem kér előleget ehhez a foglaláshoz. Az előleg fizetési határideje az API-n keresztül nem kérdezhető le, csak a fenti három mező érhető el."},"confirmedAt":{"type":["string","null"],"format":"date-time","description":"A visszaigazolás időpontja UTC-ben. `null`, amíg a foglalás nem került `confirmed` állapotba."},"cancelledAt":{"type":["string","null"],"format":"date-time","description":"A lemondás időpontja UTC-ben. `null`, ha a foglalás nincs lemondva."},"cancelReason":{"type":["string","null"],"description":"A lemondás oka. A `POST /reservations/{id}/cancel` a törzsben küldött `reason` mezőt menti ide; ha nem küldesz okot, a rögzített `Étterem lemondta` szöveget, mert a hívást a rendszer a hely nevében végzi. Ha a vendég mondta le a saját kezelőlinkjéről, `Vendég lemondta (online)` szerepel itt. Előfordulnak egyéb, nem API-eredetű értékek is: a munkatárs által a kezelőfelületen beírt szabad szöveg, a telefonos lemondás címkéje, vagy átvett adatoknál a törlés jelölése. A mező tehát ember által olvasható, magyar nyelvű címke, NEM zárt felsorolás - programozott elágazást ne erre építs. `null`, ha a foglalás nincs lemondva, vagy ha a felületen ok megadása nélkül mondták le."},"createdAt":{"type":"string","format":"date-time","description":"A foglalás létrejöttének időpontja UTC-ben."},"updatedAt":{"type":"string","format":"date-time","description":"Az utolsó módosítás időpontja UTC-ben. Ezt a mezőt szűri az `updatedSince` query-paraméter szinkronizáláshoz."}},"required":["id","date","startTime","endTime","partySize","status","source","type","title","customerName","customerPhone","customerEmail","contactId","notes","specialRequests","customFieldValues","deposit","confirmedAt","cancelledAt","cancelReason","createdAt","updatedAt"]},"modified":{"type":"boolean","enum":[true],"description":"Mindig `true`, ha a módosítás átment. Nem jelzi, hogy a módosítás megváltoztatta-e a foglalás `status` vagy `deposit` mezőjét - azt a visszaadott foglalásból olvasd ki."}},"required":["reservation","modified"]}}}},"400":{"description":"invalid_request: A séma-validáció bukott, vagy hiányzik egy kötelező paraméter. A `details[]` mezőnként sorolja fel az okot.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"401":{"description":"unauthorized: Hiányzó, hibás formátumú, ismeretlen, visszavont vagy lejárt token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"403":{"description":"forbidden: A token nem rendelkezik a szükséges scope-pal, a hívó IP nincs a kulcs allowlistáján, a fiók csomagja nem tartalmaz API-hozzáférést, vagy a fiók írás-tiltott (bemutató mód).","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"404":{"description":"not_found: Az erőforrás nem létezik EBBEN a fiókban. Egy másik fiókhoz tartozó azonosító is ezt adja - a kettő szándékosan megkülönböztethetetlen.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"422":{"description":"reservation_rejected: Szintaktikailag helyes foglalás-kérés, amit egy üzleti szabály utasít el: nincs szabad asztal az adott időpontra, a hely zárva van, a dátum a múltban van, vagy a foglalás jelenlegi állapotából nem vezet út a kért állapotba (például egy már lemondott foglalás leültetése).","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"429":{"description":"rate_limited: A percalapú sebességkorlát (alapból 120 kérés/perc/kulcs) túllépve.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"500":{"description":"internal_error: Váratlan szerverhiba. Egyetlen végponton (`POST /contacts`) ugyanez a hiba a rövidebb `internal` kóddal érkezik - kezeld a kettőt azonosan.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}}}}},"/reservations/{id}/status":{"post":{"operationId":"reservations.status","tags":["reservations"],"summary":"Státuszváltás (visszaigazolás, leültetés, lezárás, meg nem jelenés)","description":"Lemondáshoz a `/cancel` végpontot használd. Kiküldi a `reservation.updated` webhookot, és - az alábbi korlátokkal - elindítja az állapothoz tartozó automatizmust: `confirmed` esetén a visszaigazoló levelet, `completed` esetén az értékelés-kérőt. Ha a törzs SÉMAILAG érvénytelen (rossz típus, ismeretlen enum-érték) ÉS az `{id}` sem létezik, a válasz `400`, nem `404` - a séma-ellenőrzés megelőzi a létezés-vizsgálatot, hogy egy formailag hibás kérés hívója se kapjon jelzést az erőforrás létezéséről. A sémailag ÉRVÉNYES, de üres `{}` törzs viszont átmegy a séma-ellenőrzésen, ezért ott a létezés-vizsgálat fut előbb: nem létező azonosítóra `404` a válasz, és csak létező erőforrásnál kapod meg a `400`-at.\n\nSzükséges scope: `reservations.manage`.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Erőforrás-azonosító"},"required":true,"description":"Erőforrás-azonosító","name":"id","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["confirmed","seated","completed","no_show"],"description":"Az új állapot. `confirmed`: a hely visszaigazolja a foglalást. `seated`: a vendég megérkezett és leült. `completed`: a vendég távozott, a foglalás lezárult. `no_show`: a vendég nem jelent meg."}},"required":["status"]}}}},"responses":{"200":{"description":"Sikeres válasz","content":{"application/json":{"schema":{"type":"object","properties":{"reservation":{"type":"object","properties":{"id":{"type":"string","description":"A foglalás állandó azonosítója. Ezt add át az `/reservations/{id}` alatti végpontoknak."},"date":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$","description":"A foglalás napja a vendéglátóhely helyi idejében."},"startTime":{"type":"string","pattern":"^([01]\\d|2[0-3]):[0-5]\\d$","description":"Az érkezés időpontja helyi idő szerint."},"endTime":{"type":"string","pattern":"^([01]\\d|2[0-3]):[0-5]\\d$","description":"A foglalás tervezett vége helyi idő szerint; az asztal ennyi ideig van lekötve. A rendszer az érkezési időponthoz adja hozzá a hely foglalási hosszát, amit a létszám növelhet (nagyobb társaság tovább marad). A nyitvatartás ebbe nem számít bele: a végidő túlnyúlhat a záráson, és éjfél után záró helynél át is fordulhat a következő naptári napra - ilyenkor kisebb, mint a `startTime` (például 23:30 + 120 perc = `01:30`), miközben a `date` a szolgáltatási napot mutatja. Időtartam-számításnál ezért: ha az `endTime` nem nagyobb a `startTime`-nál, egy napot hozzá kell adni."},"partySize":{"type":"integer","description":"A vendégek száma, gyerekekkel együtt."},"status":{"type":"string","enum":["pending","pending_payment","confirmed","seated","completed","cancelled","no_show","walk_in"],"description":"A foglalás aktuális állapota. Az átmeneteket a `/reservations/{id}/status` és a `/reservations/{id}/cancel` végpont vezérli."},"source":{"type":"string","description":"Honnan érkezett a foglalás. Az API-n keresztül létrehozottak mindig `api` értéket kapnak, a saját online foglalási űrlapunkról érkezők `online`-t, az átemelt vagy importált foglalások `third_party`-t. További előforduló értékek: `phone`, `walk_in`, `email`, `app`. A mező szabad szöveg, nem zárt felsorolás: régi vagy importált sor ezeken kívüli értéket is hordozhat, ezért ismeretlen forrásra is fel kell készülni."},"type":{"type":"string","description":"`reservation` egy hétköznapi asztalfoglalásnál, `event` egy rendezvénynél. A rendezvényeknek van `title`-jük."},"title":{"type":["string","null"],"description":"A rendezvény neve. Csak `type=event` esetén van kitöltve, egyébként `null`."},"customerName":{"type":"string","description":"A foglaló neve, ahogy megadta. Mindig jelen van a válaszban, de lehet ÜRES string: az oszlop alapértéke üres, és a nem az API-n keresztül létrejött foglalásoknál (importált sorok, a felületen név nélkül rögzített foglalás) így is maradhat. Megjelenítéshez vagy kulcsképzéshez számíts az üres értékre."},"customerPhone":{"type":"string","description":"A foglaló telefonszáma, ahogy megadta. Nincs egységesítve, tehát nem feltétlenül E.164 alakú. Az oszlop alapértéke üres string, ezért ez a mező is lehet üres."},"customerEmail":{"type":["string","null"],"description":"A foglaló e-mail címe, ha megadta. Nincs formátum-ellenőrizve."},"contactId":{"type":["string","null"],"description":"Annak a CRM-kontaktnak az azonosítója, amelyhez a foglalás tartozik. A `POST /reservations` mindig kapcsol kontaktot: e-mail cím vagy telefonszám alapján megkeresi a meglévőt, vagy újat hoz létre - a saját felületeinken felvett foglalás is így viselkedik. `null` csak olyan sornál fordul elő, amelyhez nem sikerült kontaktot rendelni (például kézzel vagy importból rögzített régebbi foglalás). A kontakt részleteit a `GET /contacts/{id}` adja."},"notes":{"type":["string","null"],"description":"A vendég szabad szöveges megjegyzése a foglaláshoz."},"specialRequests":{"type":["string","null"],"description":"Külön kérés (például allergia, ünnepi alkalom, ültetési igény), ha a felvevő felület gyűjti."},"customFieldValues":{"type":["object","null"],"additionalProperties":{"type":"string"},"description":"A foglalási űrlap egyedi mezőinek értékei, mezőazonosító szerint. Minden érték string."},"deposit":{"type":["object","null"],"properties":{"amount":{"type":"number","description":"Az előleg fizetendő összege forintban. Százalékos típusnál ez a már kiszámított összeg, ne számold újra."},"type":{"type":"string","enum":["fixed","percentage"],"description":"`fixed`: a hely által beállított rögzített forintösszeg. `percentage`: százalékos előleg, amelynek alapja NEM a fogyasztás vagy a rendelés értéke, hanem egy fejenkénti, rendszerszintű 5000 Ft-os becsült érték - a fizetendő összeg `kerekítés(létszám * 5000 * százalék / 100)`."},"status":{"type":"string","enum":["pending","paid","refunded","forfeited"],"description":"`pending`: még nem fizették be. `paid`: beérkezett. `refunded`: visszatérítve. `forfeited`: a vendég elbukta (például meg nem jelenés miatt)."}},"required":["amount","type","status"],"description":"Az előleg adatai, ha a foglaláshoz tartozik. `null`, ha a hely nem kér előleget ehhez a foglaláshoz. Az előleg fizetési határideje az API-n keresztül nem kérdezhető le, csak a fenti három mező érhető el."},"confirmedAt":{"type":["string","null"],"format":"date-time","description":"A visszaigazolás időpontja UTC-ben. `null`, amíg a foglalás nem került `confirmed` állapotba."},"cancelledAt":{"type":["string","null"],"format":"date-time","description":"A lemondás időpontja UTC-ben. `null`, ha a foglalás nincs lemondva."},"cancelReason":{"type":["string","null"],"description":"A lemondás oka. A `POST /reservations/{id}/cancel` a törzsben küldött `reason` mezőt menti ide; ha nem küldesz okot, a rögzített `Étterem lemondta` szöveget, mert a hívást a rendszer a hely nevében végzi. Ha a vendég mondta le a saját kezelőlinkjéről, `Vendég lemondta (online)` szerepel itt. Előfordulnak egyéb, nem API-eredetű értékek is: a munkatárs által a kezelőfelületen beírt szabad szöveg, a telefonos lemondás címkéje, vagy átvett adatoknál a törlés jelölése. A mező tehát ember által olvasható, magyar nyelvű címke, NEM zárt felsorolás - programozott elágazást ne erre építs. `null`, ha a foglalás nincs lemondva, vagy ha a felületen ok megadása nélkül mondták le."},"createdAt":{"type":"string","format":"date-time","description":"A foglalás létrejöttének időpontja UTC-ben."},"updatedAt":{"type":"string","format":"date-time","description":"Az utolsó módosítás időpontja UTC-ben. Ezt a mezőt szűri az `updatedSince` query-paraméter szinkronizáláshoz."}},"required":["id","date","startTime","endTime","partySize","status","source","type","title","customerName","customerPhone","customerEmail","contactId","notes","specialRequests","customFieldValues","deposit","confirmedAt","cancelledAt","cancelReason","createdAt","updatedAt"]}},"required":["reservation"]}}}},"400":{"description":"invalid_request: A séma-validáció bukott, vagy hiányzik egy kötelező paraméter. A `details[]` mezőnként sorolja fel az okot.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"401":{"description":"unauthorized: Hiányzó, hibás formátumú, ismeretlen, visszavont vagy lejárt token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"403":{"description":"forbidden: A token nem rendelkezik a szükséges scope-pal, a hívó IP nincs a kulcs allowlistáján, a fiók csomagja nem tartalmaz API-hozzáférést, vagy a fiók írás-tiltott (bemutató mód).","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"404":{"description":"not_found: Az erőforrás nem létezik EBBEN a fiókban. Egy másik fiókhoz tartozó azonosító is ezt adja - a kettő szándékosan megkülönböztethetetlen.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"422":{"description":"reservation_rejected: Szintaktikailag helyes foglalás-kérés, amit egy üzleti szabály utasít el: nincs szabad asztal az adott időpontra, a hely zárva van, a dátum a múltban van, vagy a foglalás jelenlegi állapotából nem vezet út a kért állapotba (például egy már lemondott foglalás leültetése).","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"429":{"description":"rate_limited: A percalapú sebességkorlát (alapból 120 kérés/perc/kulcs) túllépve.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"500":{"description":"internal_error: Váratlan szerverhiba. Egyetlen végponton (`POST /contacts`) ugyanez a hiba a rövidebb `internal` kóddal érkezik - kezeld a kettőt azonosan.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}}}}},"/availability":{"get":{"operationId":"availability.day","tags":["availability"],"summary":"Egy nap szabad időpontjai","description":"A foglalási folyamat első lépése: megmondja, mikor lehet asztalt kérni az adott napra és létszámra. A listából kimaradnak a már betelt sávok, a zárva tartó napok és a nyitvatartáson kívüli időpontok - az utolsó beülés mindig annyival a zárás előtt van, hogy a teljes étkezési idő beleférjen -, a mai napon pedig a hely minimális előjegyzési idején (alapértelmezés: 2 óra) belüli időpontok is - ezért egy késő esti, mai napra szóló lekérdezés akkor is üres tömböt adhat, ha a hely nyitva van és teljesen szabad. Ha a hely kikapcsolta az aznapi foglalást, a mai nap mindig üres. FIGYELEM: a foglalási időablakot ez a végpont nem vizsgálja - múltbeli dátumra, illetve a megengedett előfoglalási időszakon (alapértelmezés: 30 nap) túli dátumra is visszaadhat idősávokat, amelyeket a `POST /reservations` utána `422` `reservation_rejected` hibával elutasít. A ténylegesen foglalható napokat a `GET /availability/month` adja meg, az az időablakot is figyelembe veszi. Üres `slots` tömb tehát nem hiba, és nem feltétlenül teltházat jelent: aznap erre a létszámra most nincs foglalható idősáv. Az itt kapott `time` értéket add át a `POST /reservations` hívásnak.\n\nSzükséges scope: `reservations.readonly`.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$","description":"A vizsgált nap a hely helyi idejében. Éjfél utáni zárásnál ez a szolgáltatási nap, vagyis az este, amelyhez a hajnali idősávok is tartoznak."},"required":true,"description":"A vizsgált nap a hely helyi idejében. Éjfél utáni zárásnál ez a szolgáltatási nap, vagyis az este, amelyhez a hajnali idősávok is tartoznak.","name":"date","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":1000,"description":"Hány főre keresel helyet. Alapértelmezés: 2. A tartományon kívüli érték nem hibázik: a rendszer a legközelebbi határra szorítja, és a válasz `partySize` mezője mutatja a ténylegesen használt számot. Az 1-1000 csak ennek a paraméternek az olvasható tartománya: a helynek saját létszám-korlátja is van (alapból 1 és 20 között, naponként felülírható), amit ez a végpont NEM érvényesít - azon kívüli létszámra is kaphatsz idősávokat, a `POST /reservations` viszont `422`-vel utasítja el."},"required":false,"description":"Hány főre keresel helyet. Alapértelmezés: 2. A tartományon kívüli érték nem hibázik: a rendszer a legközelebbi határra szorítja, és a válasz `partySize` mezője mutatja a ténylegesen használt számot. Az 1-1000 csak ennek a paraméternek az olvasható tartománya: a helynek saját létszám-korlátja is van (alapból 1 és 20 között, naponként felülírható), amit ez a végpont NEM érvényesít - azon kívüli létszámra is kaphatsz idősávokat, a `POST /reservations` viszont `422`-vel utasítja el.","name":"partySize","in":"query"}],"responses":{"200":{"description":"Sikeres válasz","content":{"application/json":{"schema":{"type":"object","properties":{"date":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$","description":"A vizsgált nap, ahogy a kérésben érkezett. Ez a szolgáltatási nap (az este), nem feltétlenül minden `time` naptári napja: éjfél utáni zárásnál a hajnali idősávok is ehhez a naphoz tartoznak."},"partySize":{"type":"integer","description":"A ténylegesen alkalmazott létszám. Eltérhet a kérésben küldöttől, ha az a megengedett tartományon kívül esett."},"slots":{"type":"array","items":{"type":"object","properties":{"time":{"type":"string","description":"Az idősáv kezdete a hely helyi ideje szerint, `HH:mm` alakban. Ezt add át a `POST /reservations` `startTime` mezőjének, a lekérdezett `date` napjával együtt. Éjfél utánig nyitva tartó helynél a lista falióra-időt ad: egy `00:30` érték naptárilag már a `date` utáni napra esik, a foglalás napja (és a `POST /reservations` `date` mezője) mégis az esti, szolgáltatási nap marad. A vendégnek mutatott dátumot ezért ne a `date` és a `time` puszta összefűzésével állítsd elő."},"availableTableIds":{"type":"array","items":{"type":"string"},"description":"A rendszer által ehhez az idősávhoz ELŐRE kiválasztott asztal(ok) azonosítói - nem a szabad asztalok listája, és nem a szabad kapacitás mértéke. Rendszerint egyetlen asztal; több elem csak akkor kerül bele, ha a létszám kizárólag asztalcsoporttal vagy asztalok összetolásával fér el. Ha a hely férőhely-alapon (nem asztalonként) számol, a tömb foglalható idősávnál is üres marad, tehát üres tömbből SOHA ne következtess foglaltságra: a foglalhatóságot az jelzi, hogy az idősáv egyáltalán szerepel a `slots` listában. Tájékoztató jellegű: a foglaláskor a rendszer maga választ asztalt, konkrét asztal nem kérhető az API-n."}},"required":["time","availableTableIds"]},"description":"A foglalható idősávok a nyitástól a zárásig, felszolgálási sorrendben - éjfél utáni zárásnál a lista a hajnali sávokkal folytatódik (... 23:30, 00:00, 00:30). A tömböt úgy használd, ahogy kaptad: a `time` string szerinti újrarendezés a `00:00`-t a lista elejére dobná. Üres tömb esetén aznap nincs foglalható idősáv erre a létszámra."}},"required":["date","partySize","slots"]}}}},"400":{"description":"invalid_request: A séma-validáció bukott, vagy hiányzik egy kötelező paraméter. A `details[]` mezőnként sorolja fel az okot.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"401":{"description":"unauthorized: Hiányzó, hibás formátumú, ismeretlen, visszavont vagy lejárt token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"403":{"description":"forbidden: A token nem rendelkezik a szükséges scope-pal, a hívó IP nincs a kulcs allowlistáján, a fiók csomagja nem tartalmaz API-hozzáférést, vagy a fiók írás-tiltott (bemutató mód).","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"429":{"description":"rate_limited: A percalapú sebességkorlát (alapból 120 kérés/perc/kulcs) túllépve.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"500":{"description":"internal_error: Váratlan szerverhiba. Egyetlen végponton (`POST /contacts`) ugyanez a hiba a rövidebb `internal` kóddal érkezik - kezeld a kettőt azonosan.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}}}}},"/availability/month":{"get":{"operationId":"availability.month","tags":["availability"],"summary":"Egy hónap foglaltsági áttekintése","description":"Naptár-nézethez: egy hónap minden napjáról megmondja, van-e legalább egy foglalható idősáv az adott létszámra. Konkrét időpontokat nem ad - azokhoz a kiválasztott napra hívd a `GET /availability` végpontot. Egyetlen hívás kiszolgál egy teljes hónapnyi naptárat, tehát ne kérdezz le napokat egyesével. A `GET /availability` végponttal szemben ez a foglalási időablakot is figyelembe veszi: a mai nap előtti és az előfoglalási időszakon (alapértelmezés: 30 nap) túli napok mindig `available: false` értéket kapnak. Ezért ugyanarra a napra a hónap `false`-ot mondhat, miközben a napi végpont idősávokat ad - ilyenkor a hónap válasza az irányadó, a foglalás ugyanis elutasítaná az időpontot.\n\nSzükséges scope: `reservations.readonly`.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"integer","minimum":2020,"maximum":2100,"description":"A vizsgált év, négy számjeggyel. Kötelező. A tartományon kívüli érték nem hibázik, a rendszer a legközelebbi határra szorítja."},"required":true,"description":"A vizsgált év, négy számjeggyel. Kötelező. A tartományon kívüli érték nem hibázik, a rendszer a legközelebbi határra szorítja.","name":"year","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":12,"description":"A vizsgált hónap, 1 (január) és 12 (december) között. Kötelező. A tartományon kívüli érték a határra szorítódik."},"required":true,"description":"A vizsgált hónap, 1 (január) és 12 (december) között. Kötelező. A tartományon kívüli érték a határra szorítódik.","name":"month","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":1000,"description":"Hány főre keresel helyet. Alapértelmezés: 2. A tartományon kívüli érték a határra szorítódik. A hely saját létszám-korlátját (alapból 1 és 20 fő között, naponként felülírható) ez a végpont nem érvényesíti, csak a foglalás - lásd `GET /availability`."},"required":false,"description":"Hány főre keresel helyet. Alapértelmezés: 2. A tartományon kívüli érték a határra szorítódik. A hely saját létszám-korlátját (alapból 1 és 20 fő között, naponként felülírható) ez a végpont nem érvényesíti, csak a foglalás - lásd `GET /availability`.","name":"partySize","in":"query"}],"responses":{"200":{"description":"Sikeres válasz","content":{"application/json":{"schema":{"type":"object","properties":{"year":{"type":"integer","description":"A ténylegesen vizsgált év - a szorítás után."},"month":{"type":"integer","description":"A ténylegesen vizsgált hónap - a szorítás után."},"partySize":{"type":"integer","description":"A ténylegesen alkalmazott létszám - a szorítás után."},"days":{"type":"array","items":{"type":"object","properties":{"date":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$","description":"A hónap egy napja. Éjfél utáni zárásnál ez a szolgáltatási nap, vagyis az este, amelyhez a hajnali idősávok is tartoznak."},"available":{"type":"boolean","description":"`true`, ha aznap van legalább egy foglalható idősáv erre a létszámra. `false` akkor is, ha a nap a foglalási időablakon kívül esik (múltbeli nap, vagy az előfoglalási időszakon túli nap), ha a hely aznap zárva tart, illetve a mai napra akkor, ha a minimális előjegyzési idő már minden hátralévő idősávot levágott."}},"required":["date","available"]},"description":"A hónap napjai időrendben, mindegyikhez egy igen/nem válasszal. A hónap minden naptári napja szerepel, a nem foglalhatók is."}},"required":["year","month","partySize","days"]}}}},"400":{"description":"invalid_request: A séma-validáció bukott, vagy hiányzik egy kötelező paraméter. A `details[]` mezőnként sorolja fel az okot.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"401":{"description":"unauthorized: Hiányzó, hibás formátumú, ismeretlen, visszavont vagy lejárt token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"403":{"description":"forbidden: A token nem rendelkezik a szükséges scope-pal, a hívó IP nincs a kulcs allowlistáján, a fiók csomagja nem tartalmaz API-hozzáférést, vagy a fiók írás-tiltott (bemutató mód).","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"429":{"description":"rate_limited: A percalapú sebességkorlát (alapból 120 kérés/perc/kulcs) túllépve.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"500":{"description":"internal_error: Váratlan szerverhiba. Egyetlen végponton (`POST /contacts`) ugyanez a hiba a rövidebb `internal` kóddal érkezik - kezeld a kettőt azonosan.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}}}}},"/contacts/batch":{"post":{"operationId":"contacts.batch","tags":["contacts"],"summary":"Kötegelt kontakt-feltöltés (max 100)","description":"Tételenkénti eredmény: egy hibás elem nem szakítja meg a többit. Sikeres elemnél `id`+`isNew`, hibásnál `error` jelenik meg - a másik oldal hiányzik a válaszból.\n\nSzükséges scope: `contacts.write`.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"contacts":{"type":"array","items":{},"minItems":1,"maxItems":100,"description":"Egy tétel elfogadott mezői megegyeznek a POST /contacts törzsével (firstName, lastName, email, phone, tags, customFields, marketingConsent, note); email vagy phone közül legalább az egyik kötelező tételenként."}},"required":["contacts"]}}}},"responses":{"200":{"description":"Sikeres válasz","content":{"application/json":{"schema":{"type":"object","properties":{"results":{"type":"array","items":{"type":"object","properties":{"index":{"type":"integer","description":"A tétel helye a beküldött `contacts` tömbben, nullától számozva. Ezzel párosítsd vissza az eredményt a saját adatodhoz."},"id":{"type":"string","description":"A létrejött vagy megtalált kontakt azonosítója. Csak sikeres tételnél van jelen."},"isNew":{"type":"boolean","description":"`true`, ha új kontakt jött létre, `false`, ha meglévőt fésült össze. Csak sikeres tételnél van jelen."},"error":{"type":"string","description":"A hiba szövege, ha ez a tétel elbukott. Csak hibás tételnél van jelen - ilyenkor az `id` és az `isNew` hiányzik."}},"required":["index"]},"description":"Tételenkénti eredmény, a beküldéssel azonos sorrendben. Egy hibás tétel nem szakítja meg a többit."},"summary":{"type":"object","properties":{"total":{"type":"integer","description":"A beküldött tételek száma."},"created":{"type":"integer","description":"Hány új kontakt jött létre."},"updated":{"type":"integer","description":"Hány meglévő kontakt frissült."},"failed":{"type":"integer","description":"Hány tétel bukott el. Ha ez nagyobb nullánál, a `results` tömbben keresd az okokat."}},"required":["total","created","updated","failed"]}},"required":["results","summary"]}}}},"400":{"description":"invalid_request: A séma-validáció bukott, vagy hiányzik egy kötelező paraméter. A `details[]` mezőnként sorolja fel az okot.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"401":{"description":"unauthorized: Hiányzó, hibás formátumú, ismeretlen, visszavont vagy lejárt token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"403":{"description":"forbidden: A token nem rendelkezik a szükséges scope-pal, a hívó IP nincs a kulcs allowlistáján, a fiók csomagja nem tartalmaz API-hozzáférést, vagy a fiók írás-tiltott (bemutató mód).","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"429":{"description":"rate_limited: A percalapú sebességkorlát (alapból 120 kérés/perc/kulcs) túllépve.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"500":{"description":"internal_error: Váratlan szerverhiba. Egyetlen végponton (`POST /contacts`) ugyanez a hiba a rövidebb `internal` kóddal érkezik - kezeld a kettőt azonosan.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}}}}},"/contacts":{"post":{"operationId":"contacts.create","tags":["contacts"],"summary":"Kontakt létrehozása vagy összefésülése","description":"Deduplikáció e-mail és telefon alapján: ha a cím vagy a szám már létezik a fiókban, a meglévő kontakt egészül ki, nem jön létre második. Az e-mail és a telefon egyenrangú: ha a kettő két KÜLÖNBÖZŐ meglévő kontaktra illeszkedik, a frissebben létrehozott kontakt frissül. A kiegészítés a kontakt ÜRES mezőit tölti ki: a már kitöltött `email` és `phone` értéket ez a végpont SOHA nem írja felül. `201` = új kontakt, `200` = meglévő találat kiegészítve - a kettőt a státuszkódból és az `isNew` mezőből is meg tudod különböztetni. Az `email` és a `phone` közül LEGALÁBB AZ EGYIKET meg kell adni, egyébként `400` a válasz. A `source` a kérésből nem állítható: új kontakt (`201`) mindig `api` forrással jön létre, meglévő találatnál (`200`) viszont az eredeti forrás megmarad (például `reservation` vagy `import`), a válasz `contact.source` mezője ilyenkor azt adja vissza.\n\nSzükséges scope: `contacts.write`.\n\nTámogatja az `Idempotency-Key` fejlécet.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"firstName":{"type":"string","description":"Keresztnév. Hosszkorlát nincs. FIGYELEM: összefésülésnél a küldött, nem üres név FELÜLÍRJA a megtalált kontakt keresztnevét - mindig a legutóbb küldött név marad érvényben. Ha a CRM-ben tárolt nevet nem akarod bántani, hagyd ki a mezőt vagy küldd üres stringgel; a hiányzó és az üres érték is érintetlenül hagyja a tároltat."},"lastName":{"type":"string","description":"Vezetéknév. Hosszkorlát nincs. FIGYELEM: összefésülésnél a küldött, nem üres név FELÜLÍRJA a megtalált kontakt vezetéknevét - mindig a legutóbb küldött név marad érvényben. Ha a CRM-ben tárolt nevet nem akarod bántani, hagyd ki a mezőt vagy küldd üres stringgel; a hiányzó és az üres érték is érintetlenül hagyja a tároltat."},"email":{"type":"string","description":"E-mail cím. Formátum-ellenőrzés nincs, a rendszer csak kisbetűsíti és a szélső szóközöket vágja le. Összefésülési azonosító: már létező címre a meglévő kontakt frissül, nem jön létre új. A telefonszámmal EGYENRANGÚ, nem élvez vele szemben elsőbbséget. FIGYELEM: ha az összefésülés a `phone` alapján talált kontaktot, és azon MÁR VAN egy - másik - e-mail cím, a beküldött cím CSENDBEN ELVÉSZ: nem íródik be, nem kerül külön mezőbe, és a válaszban a régi cím jön vissza `200`-zal. Meglévő e-mail cím lecseréléséhez a `PATCH /contacts/{id}` végpontot hívd. Az `email` és a `phone` közül legalább az egyiket meg kell adni."},"phone":{"type":"string","description":"Telefonszám. Formátum- és hosszellenőrzés nincs, a rendszer viszont MINDEN szóközt eltávolít belőle tárolás előtt (`+36 30 123 4567` -> `+36301234567`); a `+`, a kötőjel és a zárójel megmarad. Az e-maillel egyenrangú összefésülési azonosító: a szám egyezése önmagában is meglévő kontaktba fésül, akkor is, ha `email`-t is küldesz. A párosítás a szóközöktől eltekintve történik, a kötőjel és a zárójel viszont számít, ezért érdemes mindig ugyanabban az alakban küldeni. Ha az `email` és a `phone` KÜLÖNBÖZŐ meglévő kontaktra illeszkedik, a rendszer a KÉSŐBB LÉTREHOZOTT kontaktot frissíti, a másikat érintetlenül hagyja. A szám is csak ÜRES mezőbe íródik be: ha a megtalált kontaktnak már van másik telefonszáma, a beküldött szám elvész; cseréhez a `PATCH /contacts/{id}` kell. Az `email` és a `phone` közül legalább az egyiket meg kell adni."},"tags":{"type":"array","items":{"type":"string"},"description":"Hozzáadandó címkék. A meglévőkhöz adódnak, nem írják felül őket."},"customFields":{"type":"object","additionalProperties":{},"description":"Egyedi kontaktmezők mezőnév szerint. A megadott kulcsok felülírják a korábbi értéket, a nem említettek érintetlenül maradnak."},"marketingConsent":{"type":"boolean","description":"Marketing hozzájárulás. `true` beállítja; `false` érvényes érték, de hozzájárulást nem von vissza vele a rendszer. Nem logikai érték nem okoz hibát, egyszerűen figyelmen kívül marad."},"note":{"type":"string","description":"Jegyzet a kontakthoz, a kontakt szabad szöveges jegyzetmezőjébe. Meglévő kontakt esetén a mező korábbi tartalma megmarad, az új szöveg egy üres sorral elválasztva alá kerül; új kontaktnál ez lesz a mező kezdőértéke. Hosszkorlát nincs. HOL LÁTSZIK: a Kapcsolatok listában a kontakt gyorsnézetét megnyitva, a `Jegyzetek` fülön, kézi bejegyzésként jelölve. NEM látszik a kontakt saját adatlapjának `Megjegyzések` fülén, és az `Aktivitás` idővonalra sem kerül fel. VISSZAOLVASÁS: az API-n keresztül nem olvasható vissza - sem a `GET /contacts/{id}`, sem a `GET /contacts/{id}/notes` válaszában nincs benne. FIGYELEM: ez NEM ugyanaz a jegyzet, amit a `/contacts/{id}/notes` végpontok kezelnek, és a két tároló között nincs átjárás. KOCKÁZAT: ha később a felületen valaki a `Jegyzetek` fülön ment, vagy egy automatizált folyamat ír jegyzetet a kontakthoz, a mező tartalma a jegyzetblokkokból íródik újra - ilyenkor az itt küldött szöveg el is veszhet. Ha megbízhatóan megmaradó, szerzővel és időbélyeggel ellátott, visszaolvasható jegyzetet akarsz, a `POST /contacts/{id}/notes` végpontot használd."}}}}}},"responses":{"200":{"description":"Válasz (200)","content":{"application/json":{"schema":{"type":"object","properties":{"contact":{"type":"object","properties":{"id":{"type":"string","description":"A kontakt állandó azonosítója. Ezt add át a `/contacts/{id}` alatti végpontoknak, és ez kerül a foglalások `contactId` mezőjébe is."},"firstName":{"type":"string","description":"Keresztnév. Ha nem ismert, üres string - sosem `null`."},"lastName":{"type":"string","description":"Vezetéknév. Ha nem ismert, üres string - sosem `null`."},"email":{"type":["string","null"],"description":"E-mail cím. `null`, ha nincs rögzítve. Az API-n létrehozott és módosított kontaktoknál kisbetűsítve tárolódik, a máshonnan (például CSV-import vagy a felület) bekerült címek viszont megőrizhetik az eredeti kis- és nagybetűket - dedupláláshoz és összevetéshez ezért mindig kisbetűsítve hasonlítsd össze. Az e-maillel EGYENRANGÚ összefésülési azonosító a telefonszám: az e-mail nem élvez elsőbbséget."},"phone":{"type":["string","null"],"description":"Telefonszám a tárolt, normalizált alakban: a rendszer rögzítéskor MINDEN szóközt eltávolít belőle, minden más karaktert (`+`, kötőjel, zárójel) érintetlenül hagy. A beküldött `+36 30 123 4567` értéket tehát `+36301234567` alakban kapod vissza. `null`, ha nincs. Az e-maillel egyenrangú összefésülési azonosító - nem csak akkor számít, ha az e-mail hiányzik."},"tags":{"type":"array","items":{"type":"string"},"description":"A kontakthoz rendelt címkék. Mindig tömb, címke nélküli kontaktnál üres. A sorrend nem garantált."},"source":{"type":"string","description":"Honnan került be a kontakt. Az API-n létrehozottak `api` értéket kapnak; a többi a keletkezés helyét jelöli (például `reservation`, `form`, `loyalty`, `website`, `import`, `manual`), a social inboxból érkezőkön pedig a platform neve áll (`facebook`, `instagram`). Szabad szöveg, nem rögzített enum - új forrás bármikor megjelenhet, ezért ismeretlen értékre is fel kell készülni."},"status":{"type":"string","description":"Az ügyfél-életciklus állapota. Négy értéket használ a rendszer: `active`, `inactive`, `vip` és `blocked`. A `blocked` üzletileg kötelező érvényű: az ilyen kontaktokat a rendszer kihagyja az e-mail- és WhatsApp-kampányok címzettjei közül, ezért ne kezeld `active`-ként. A mező az adatbázisban szabad szöveg, így örökölt vagy importált sorokon ettől eltérő érték is előfordulhat - ismeretlen értéket sose vegyél alapból aktívnak. Az API-n a mező nem írható; az itt létrehozott kontaktok `active` státuszt kapnak."},"customFields":{"type":"object","additionalProperties":{},"description":"A fiók egyedi kontaktmezői, mezőnév szerint. Az értékek típusa a mező típusától függ, ezért itt tetszőleges JSON érték állhat. Mindig objektum, üresen `{}`."},"marketingConsent":{"type":"boolean","description":"Van-e érvényes marketing hozzájárulás. `false`, ha nincs vagy visszavonták."},"createdAt":{"type":"string","format":"date-time","description":"A kontakt létrejöttének időpontja UTC-ben."},"updatedAt":{"type":"string","format":"date-time","description":"Az utolsó módosítás időpontja UTC-ben. Ezt szűri az `updatedSince` query-paraméter szinkronizáláshoz."}},"required":["id","firstName","lastName","email","phone","tags","source","status","customFields","marketingConsent","createdAt","updatedAt"]},"isNew":{"type":"boolean","enum":[false],"description":"Mindig `false` ezen a státuszon: a kontakt már létezett."},"changed":{"type":"boolean","description":"Jelenleg MINDIG `true`: az összefésülés a meglévő kontaktra is ráír, mezőszintű összehasonlítás nincs. Nem jelzi megbízhatóan sem azt, hogy változott-e bármelyik mező, sem azt, hogy minden küldött érték rögzült. Ne építs rá \"nem történt változás\" ágat - a mező a későbbi, valódi mező-diffhez van fenntartva. Ha ellenőrizni akarod, vesd össze a válasz `contact` mezőit a beküldött értékekkel."}},"required":["contact","isNew","changed"]}}}},"201":{"description":"Sikeres válasz","content":{"application/json":{"schema":{"type":"object","properties":{"contact":{"type":"object","properties":{"id":{"type":"string","description":"A kontakt állandó azonosítója. Ezt add át a `/contacts/{id}` alatti végpontoknak, és ez kerül a foglalások `contactId` mezőjébe is."},"firstName":{"type":"string","description":"Keresztnév. Ha nem ismert, üres string - sosem `null`."},"lastName":{"type":"string","description":"Vezetéknév. Ha nem ismert, üres string - sosem `null`."},"email":{"type":["string","null"],"description":"E-mail cím. `null`, ha nincs rögzítve. Az API-n létrehozott és módosított kontaktoknál kisbetűsítve tárolódik, a máshonnan (például CSV-import vagy a felület) bekerült címek viszont megőrizhetik az eredeti kis- és nagybetűket - dedupláláshoz és összevetéshez ezért mindig kisbetűsítve hasonlítsd össze. Az e-maillel EGYENRANGÚ összefésülési azonosító a telefonszám: az e-mail nem élvez elsőbbséget."},"phone":{"type":["string","null"],"description":"Telefonszám a tárolt, normalizált alakban: a rendszer rögzítéskor MINDEN szóközt eltávolít belőle, minden más karaktert (`+`, kötőjel, zárójel) érintetlenül hagy. A beküldött `+36 30 123 4567` értéket tehát `+36301234567` alakban kapod vissza. `null`, ha nincs. Az e-maillel egyenrangú összefésülési azonosító - nem csak akkor számít, ha az e-mail hiányzik."},"tags":{"type":"array","items":{"type":"string"},"description":"A kontakthoz rendelt címkék. Mindig tömb, címke nélküli kontaktnál üres. A sorrend nem garantált."},"source":{"type":"string","description":"Honnan került be a kontakt. Az API-n létrehozottak `api` értéket kapnak; a többi a keletkezés helyét jelöli (például `reservation`, `form`, `loyalty`, `website`, `import`, `manual`), a social inboxból érkezőkön pedig a platform neve áll (`facebook`, `instagram`). Szabad szöveg, nem rögzített enum - új forrás bármikor megjelenhet, ezért ismeretlen értékre is fel kell készülni."},"status":{"type":"string","description":"Az ügyfél-életciklus állapota. Négy értéket használ a rendszer: `active`, `inactive`, `vip` és `blocked`. A `blocked` üzletileg kötelező érvényű: az ilyen kontaktokat a rendszer kihagyja az e-mail- és WhatsApp-kampányok címzettjei közül, ezért ne kezeld `active`-ként. A mező az adatbázisban szabad szöveg, így örökölt vagy importált sorokon ettől eltérő érték is előfordulhat - ismeretlen értéket sose vegyél alapból aktívnak. Az API-n a mező nem írható; az itt létrehozott kontaktok `active` státuszt kapnak."},"customFields":{"type":"object","additionalProperties":{},"description":"A fiók egyedi kontaktmezői, mezőnév szerint. Az értékek típusa a mező típusától függ, ezért itt tetszőleges JSON érték állhat. Mindig objektum, üresen `{}`."},"marketingConsent":{"type":"boolean","description":"Van-e érvényes marketing hozzájárulás. `false`, ha nincs vagy visszavonták."},"createdAt":{"type":"string","format":"date-time","description":"A kontakt létrejöttének időpontja UTC-ben."},"updatedAt":{"type":"string","format":"date-time","description":"Az utolsó módosítás időpontja UTC-ben. Ezt szűri az `updatedSince` query-paraméter szinkronizáláshoz."}},"required":["id","firstName","lastName","email","phone","tags","source","status","customFields","marketingConsent","createdAt","updatedAt"]},"isNew":{"type":"boolean","enum":[true],"description":"Mindig `true` ezen a státuszon: új kontakt jött létre."},"changed":{"type":"boolean","description":"Új kontaktnál mindig `true`."}},"required":["contact","isNew","changed"]}}}},"400":{"description":"invalid_request: A séma-validáció bukott, vagy hiányzik egy kötelező paraméter. A `details[]` mezőnként sorolja fel az okot.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"401":{"description":"unauthorized: Hiányzó, hibás formátumú, ismeretlen, visszavont vagy lejárt token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"403":{"description":"forbidden: A token nem rendelkezik a szükséges scope-pal, a hívó IP nincs a kulcs allowlistáján, a fiók csomagja nem tartalmaz API-hozzáférést, vagy a fiók írás-tiltott (bemutató mód).","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"429":{"description":"rate_limited: A percalapú sebességkorlát (alapból 120 kérés/perc/kulcs) túllépve.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"500":{"description":"internal_error: Váratlan szerverhiba. Egyetlen végponton (`POST /contacts`) ugyanez a hiba a rövidebb `internal` kóddal érkezik - kezeld a kettőt azonosan.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}}}},"get":{"operationId":"contacts.list","tags":["contacts"],"summary":"Kontaktok keresése vagy listázása","description":"`email` vagy `phone` megadásával célzott keresés (max 20 találat, a válasz ekkor nem tartalmaz `limit`/`offset` mezőt), mindkettő megadásakor a két feltétel ÉS-kapcsolatban szűr; ezek nélkül lapozott lista (`limit`/`offset` mezőkkel). A `tag` és `updatedSince` szűrők csak lista-módban érvényesülnek, egymással kombinálhatók.\n\nSzükséges scope: `contacts.readonly`.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Keresés e-mail címre. A teljes címnek egyeznie kell (részleges egyezés nincs), de a kis- és nagybetű nem számít: a rendszer mindkét oldalt kisbetűsíti, így a `Vendeg@Pelda.hu` és a `vendeg@pelda.hu` ugyanazt a sort találja meg. Megadásakor a végpont keresés-módba vált: legfeljebb 20 találat, `limit`/`offset` nélkül."},"required":false,"description":"Keresés e-mail címre. A teljes címnek egyeznie kell (részleges egyezés nincs), de a kis- és nagybetű nem számít: a rendszer mindkét oldalt kisbetűsíti, így a `Vendeg@Pelda.hu` és a `vendeg@pelda.hu` ugyanazt a sort találja meg. Megadásakor a végpont keresés-módba vált: legfeljebb 20 találat, `limit`/`offset` nélkül.","name":"email","in":"query"},{"schema":{"type":"string","description":"Keresés telefonszámra. Ugyanúgy keresés-módba vált, mint az `email`; ha az `email` is meg van adva, a két feltétel ÉS-kapcsolatban szűr, nem VAGY. Az összevetés előtt MINDEN szóköz eltűnik mindkét oldalról, tehát a `+36 30 123 4567` és a `+36301234567` ugyanazt a sort találja meg. Ezen túl viszont karakterre egyeznie kell: a kötőjel, a zárójel és az országhívó alakja számít, a `06301234567` NEM találja meg a `+36301234567`-et. A szám többi részét ezért abban az alakban küldd, ahogyan létrehoztad."},"required":false,"description":"Keresés telefonszámra. Ugyanúgy keresés-módba vált, mint az `email`; ha az `email` is meg van adva, a két feltétel ÉS-kapcsolatban szűr, nem VAGY. Az összevetés előtt MINDEN szóköz eltűnik mindkét oldalról, tehát a `+36 30 123 4567` és a `+36301234567` ugyanazt a sort találja meg. Ezen túl viszont karakterre egyeznie kell: a kötőjel, a zárójel és az országhívó alakja számít, a `06301234567` NEM találja meg a `+36301234567`-et. A szám többi részét ezért abban az alakban küldd, ahogyan létrehoztad.","name":"phone","in":"query"},{"schema":{"type":"string","description":"Szűrés egy címkére. Csak lista-módban érvényesül, tehát `email` vagy `phone` mellett nincs hatása."},"required":false,"description":"Szűrés egy címkére. Csak lista-módban érvényesül, tehát `email` vagy `phone` mellett nincs hatása.","name":"tag","in":"query"},{"schema":{"type":"string","description":"Csak az ezóta módosult kontaktok. Csak lista-módban érvényesül. Szinkronizáláshoz: tedd el a legutolsó kapott `updatedAt` értéket, és azt add vissza."},"required":false,"description":"Csak az ezóta módosult kontaktok. Csak lista-módban érvényesül. Szinkronizáláshoz: tedd el a legutolsó kapott `updatedAt` értéket, és azt add vissza.","name":"updatedSince","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":200,"default":50,"description":"Találatok maximális száma (1-200, alapértelmezés 50; a tartományon kívüli érték a határra szorítódik, nem hibát ad)"},"required":false,"description":"Találatok maximális száma (1-200, alapértelmezés 50; a tartományon kívüli érték a határra szorítódik, nem hibát ad)","name":"limit","in":"query"},{"schema":{"type":"integer","minimum":0,"maximum":1000000,"default":0,"description":"Hány találatot ugorjon át (a tartományon kívüli érték a határra szorítódik, nem hibát ad)"},"required":false,"description":"Hány találatot ugorjon át (a tartományon kívüli érték a határra szorítódik, nem hibát ad)","name":"offset","in":"query"}],"responses":{"200":{"description":"Sikeres válasz","content":{"application/json":{"schema":{"type":"object","properties":{"contacts":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"A kontakt állandó azonosítója. Ezt add át a `/contacts/{id}` alatti végpontoknak, és ez kerül a foglalások `contactId` mezőjébe is."},"firstName":{"type":"string","description":"Keresztnév. Ha nem ismert, üres string - sosem `null`."},"lastName":{"type":"string","description":"Vezetéknév. Ha nem ismert, üres string - sosem `null`."},"email":{"type":["string","null"],"description":"E-mail cím. `null`, ha nincs rögzítve. Az API-n létrehozott és módosított kontaktoknál kisbetűsítve tárolódik, a máshonnan (például CSV-import vagy a felület) bekerült címek viszont megőrizhetik az eredeti kis- és nagybetűket - dedupláláshoz és összevetéshez ezért mindig kisbetűsítve hasonlítsd össze. Az e-maillel EGYENRANGÚ összefésülési azonosító a telefonszám: az e-mail nem élvez elsőbbséget."},"phone":{"type":["string","null"],"description":"Telefonszám a tárolt, normalizált alakban: a rendszer rögzítéskor MINDEN szóközt eltávolít belőle, minden más karaktert (`+`, kötőjel, zárójel) érintetlenül hagy. A beküldött `+36 30 123 4567` értéket tehát `+36301234567` alakban kapod vissza. `null`, ha nincs. Az e-maillel egyenrangú összefésülési azonosító - nem csak akkor számít, ha az e-mail hiányzik."},"tags":{"type":"array","items":{"type":"string"},"description":"A kontakthoz rendelt címkék. Mindig tömb, címke nélküli kontaktnál üres. A sorrend nem garantált."},"source":{"type":"string","description":"Honnan került be a kontakt. Az API-n létrehozottak `api` értéket kapnak; a többi a keletkezés helyét jelöli (például `reservation`, `form`, `loyalty`, `website`, `import`, `manual`), a social inboxból érkezőkön pedig a platform neve áll (`facebook`, `instagram`). Szabad szöveg, nem rögzített enum - új forrás bármikor megjelenhet, ezért ismeretlen értékre is fel kell készülni."},"status":{"type":"string","description":"Az ügyfél-életciklus állapota. Négy értéket használ a rendszer: `active`, `inactive`, `vip` és `blocked`. A `blocked` üzletileg kötelező érvényű: az ilyen kontaktokat a rendszer kihagyja az e-mail- és WhatsApp-kampányok címzettjei közül, ezért ne kezeld `active`-ként. A mező az adatbázisban szabad szöveg, így örökölt vagy importált sorokon ettől eltérő érték is előfordulhat - ismeretlen értéket sose vegyél alapból aktívnak. Az API-n a mező nem írható; az itt létrehozott kontaktok `active` státuszt kapnak."},"customFields":{"type":"object","additionalProperties":{},"description":"A fiók egyedi kontaktmezői, mezőnév szerint. Az értékek típusa a mező típusától függ, ezért itt tetszőleges JSON érték állhat. Mindig objektum, üresen `{}`."},"marketingConsent":{"type":"boolean","description":"Van-e érvényes marketing hozzájárulás. `false`, ha nincs vagy visszavonták."},"createdAt":{"type":"string","format":"date-time","description":"A kontakt létrejöttének időpontja UTC-ben."},"updatedAt":{"type":"string","format":"date-time","description":"Az utolsó módosítás időpontja UTC-ben. Ezt szűri az `updatedSince` query-paraméter szinkronizáláshoz."}},"required":["id","firstName","lastName","email","phone","tags","source","status","customFields","marketingConsent","createdAt","updatedAt"]},"description":"A találatok. Lista-módban egy lapnyi, keresés-módban legfeljebb 20 elem."},"limit":{"type":"integer","description":"Az alkalmazott lapméret. Keresés-módban (`email` vagy `phone` szűrővel) EZ A MEZŐ HIÁNYZIK a válaszból."},"offset":{"type":"integer","description":"Az alkalmazott eltolás. Keresés-módban ez a mező is hiányzik."}},"required":["contacts"]}}}},"400":{"description":"invalid_request: A séma-validáció bukott, vagy hiányzik egy kötelező paraméter. A `details[]` mezőnként sorolja fel az okot.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"401":{"description":"unauthorized: Hiányzó, hibás formátumú, ismeretlen, visszavont vagy lejárt token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"403":{"description":"forbidden: A token nem rendelkezik a szükséges scope-pal, a hívó IP nincs a kulcs allowlistáján, a fiók csomagja nem tartalmaz API-hozzáférést, vagy a fiók írás-tiltott (bemutató mód).","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"429":{"description":"rate_limited: A percalapú sebességkorlát (alapból 120 kérés/perc/kulcs) túllépve.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"500":{"description":"internal_error: Váratlan szerverhiba. Egyetlen végponton (`POST /contacts`) ugyanez a hiba a rövidebb `internal` kóddal érkezik - kezeld a kettőt azonosan.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}}}}},"/contacts/{id}":{"delete":{"operationId":"contacts.delete","tags":["contacts"],"summary":"Kontakt törlése","description":"Törli a kontakt rekordot. A művelet NEM visszavonható, és külön `contacts.delete` scope kell hozzá - a `contacts.write` nem elég. FIGYELEM: ez NEM teljes GDPR-adattörlés. A kontakthoz kötött sorok (jegyzetek, aktivitás, foglalások, rendelések, deal-ek, feladatok, hűségpont-tranzakciók, utalványok, értékelések) MEGMARADNAK, csak a kontakt-hivatkozásuk nullázódik. Az ezekben tárolt személyes adat (például a jegyzet szövege és a rögzítő neve, a foglaláson a vendég neve, telefonszáma és e-mail címe) a rendszerben marad. Ha érintetti törlési kérelmet teljesítesz, ez a végpont önmagában nem elegendő. Nem létező azonosítóra `404`. A törlés NEM mindig sikerül: ha a kontakt egy automatizmus cél (Goal) lépésén várakozik, a hozzá tartozó belső sor jelenleg megakadályozza a törlést, és a válasz `500` - a kontakt ilyenkor VÁLTOZATLANUL megmarad.\n\nSzükséges scope: `contacts.delete`.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Erőforrás-azonosító"},"required":true,"description":"Erőforrás-azonosító","name":"id","in":"path"}],"responses":{"200":{"description":"Sikeres válasz","content":{"application/json":{"schema":{"type":"object","properties":{"deleted":{"type":"boolean","enum":[true],"description":"Mindig `true`, ha a törlés megtörtént."},"id":{"type":"string","description":"A törölt kontakt azonosítója - visszaigazolásként, hogy tényleg azt törölted, amit akartál."}},"required":["deleted","id"]}}}},"401":{"description":"unauthorized: Hiányzó, hibás formátumú, ismeretlen, visszavont vagy lejárt token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"403":{"description":"forbidden: A token nem rendelkezik a szükséges scope-pal, a hívó IP nincs a kulcs allowlistáján, a fiók csomagja nem tartalmaz API-hozzáférést, vagy a fiók írás-tiltott (bemutató mód).","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"404":{"description":"not_found: Az erőforrás nem létezik EBBEN a fiókban. Egy másik fiókhoz tartozó azonosító is ezt adja - a kettő szándékosan megkülönböztethetetlen.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"429":{"description":"rate_limited: A percalapú sebességkorlát (alapból 120 kérés/perc/kulcs) túllépve.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"500":{"description":"internal_error: Váratlan szerverhiba. Egyetlen végponton (`POST /contacts`) ugyanez a hiba a rövidebb `internal` kóddal érkezik - kezeld a kettőt azonosan.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}}}},"get":{"operationId":"contacts.get","tags":["contacts"],"summary":"Egy kontakt lekérdezése","description":"Egyetlen kontakt teljes, aktuális adatlapja azonosító alapján. Jegyzeteket nem tartalmaz: a `POST /contacts/{id}/notes` jegyzeteit a `GET /contacts/{id}/notes` adja vissza, a kontakt létrehozásakor küldött `note` mező tartalmát viszont egyetlen végpont sem adja vissza - az csak a kezelőfelületen, a kontakt gyorsnézetének `Jegyzetek` fülén látszik. Más fiók kontaktjára `404` a válasz.\n\nSzükséges scope: `contacts.readonly`.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Erőforrás-azonosító"},"required":true,"description":"Erőforrás-azonosító","name":"id","in":"path"}],"responses":{"200":{"description":"Sikeres válasz","content":{"application/json":{"schema":{"type":"object","properties":{"contact":{"type":"object","properties":{"id":{"type":"string","description":"A kontakt állandó azonosítója. Ezt add át a `/contacts/{id}` alatti végpontoknak, és ez kerül a foglalások `contactId` mezőjébe is."},"firstName":{"type":"string","description":"Keresztnév. Ha nem ismert, üres string - sosem `null`."},"lastName":{"type":"string","description":"Vezetéknév. Ha nem ismert, üres string - sosem `null`."},"email":{"type":["string","null"],"description":"E-mail cím. `null`, ha nincs rögzítve. Az API-n létrehozott és módosított kontaktoknál kisbetűsítve tárolódik, a máshonnan (például CSV-import vagy a felület) bekerült címek viszont megőrizhetik az eredeti kis- és nagybetűket - dedupláláshoz és összevetéshez ezért mindig kisbetűsítve hasonlítsd össze. Az e-maillel EGYENRANGÚ összefésülési azonosító a telefonszám: az e-mail nem élvez elsőbbséget."},"phone":{"type":["string","null"],"description":"Telefonszám a tárolt, normalizált alakban: a rendszer rögzítéskor MINDEN szóközt eltávolít belőle, minden más karaktert (`+`, kötőjel, zárójel) érintetlenül hagy. A beküldött `+36 30 123 4567` értéket tehát `+36301234567` alakban kapod vissza. `null`, ha nincs. Az e-maillel egyenrangú összefésülési azonosító - nem csak akkor számít, ha az e-mail hiányzik."},"tags":{"type":"array","items":{"type":"string"},"description":"A kontakthoz rendelt címkék. Mindig tömb, címke nélküli kontaktnál üres. A sorrend nem garantált."},"source":{"type":"string","description":"Honnan került be a kontakt. Az API-n létrehozottak `api` értéket kapnak; a többi a keletkezés helyét jelöli (például `reservation`, `form`, `loyalty`, `website`, `import`, `manual`), a social inboxból érkezőkön pedig a platform neve áll (`facebook`, `instagram`). Szabad szöveg, nem rögzített enum - új forrás bármikor megjelenhet, ezért ismeretlen értékre is fel kell készülni."},"status":{"type":"string","description":"Az ügyfél-életciklus állapota. Négy értéket használ a rendszer: `active`, `inactive`, `vip` és `blocked`. A `blocked` üzletileg kötelező érvényű: az ilyen kontaktokat a rendszer kihagyja az e-mail- és WhatsApp-kampányok címzettjei közül, ezért ne kezeld `active`-ként. A mező az adatbázisban szabad szöveg, így örökölt vagy importált sorokon ettől eltérő érték is előfordulhat - ismeretlen értéket sose vegyél alapból aktívnak. Az API-n a mező nem írható; az itt létrehozott kontaktok `active` státuszt kapnak."},"customFields":{"type":"object","additionalProperties":{},"description":"A fiók egyedi kontaktmezői, mezőnév szerint. Az értékek típusa a mező típusától függ, ezért itt tetszőleges JSON érték állhat. Mindig objektum, üresen `{}`."},"marketingConsent":{"type":"boolean","description":"Van-e érvényes marketing hozzájárulás. `false`, ha nincs vagy visszavonták."},"createdAt":{"type":"string","format":"date-time","description":"A kontakt létrejöttének időpontja UTC-ben."},"updatedAt":{"type":"string","format":"date-time","description":"Az utolsó módosítás időpontja UTC-ben. Ezt szűri az `updatedSince` query-paraméter szinkronizáláshoz."}},"required":["id","firstName","lastName","email","phone","tags","source","status","customFields","marketingConsent","createdAt","updatedAt"]}},"required":["contact"]}}}},"401":{"description":"unauthorized: Hiányzó, hibás formátumú, ismeretlen, visszavont vagy lejárt token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"403":{"description":"forbidden: A token nem rendelkezik a szükséges scope-pal, a hívó IP nincs a kulcs allowlistáján, a fiók csomagja nem tartalmaz API-hozzáférést, vagy a fiók írás-tiltott (bemutató mód).","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"404":{"description":"not_found: Az erőforrás nem létezik EBBEN a fiókban. Egy másik fiókhoz tartozó azonosító is ezt adja - a kettő szándékosan megkülönböztethetetlen.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"429":{"description":"rate_limited: A percalapú sebességkorlát (alapból 120 kérés/perc/kulcs) túllépve.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"500":{"description":"internal_error: Váratlan szerverhiba. Egyetlen végponton (`POST /contacts`) ugyanez a hiba a rövidebb `internal` kóddal érkezik - kezeld a kettőt azonosan.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}}}},"patch":{"operationId":"contacts.update","tags":["contacts"],"summary":"Kontakt mezőinek módosítása","description":"Csak a törzsben szereplő mezők változnak, a többi érintetlen marad. Egy mező kiürítéséhez küldd `null` értékkel; a kulcs elhagyása nem törli. Legalább egy módosítható mezőt meg kell adni (`firstName`, `lastName`, `email`, `phone`, `tags`, `customFields`, `marketingConsent`), egyébként `400` a válasz. Ha a törzs SÉMAILAG érvénytelen (rossz típus, ismeretlen enum-érték) ÉS az `{id}` sem létezik, a válasz `400`, nem `404` - a séma-ellenőrzés megelőzi a létezés-vizsgálatot, hogy egy formailag hibás kérés hívója se kapjon jelzést az erőforrás létezéséről. A sémailag ÉRVÉNYES, de üres `{}` törzs viszont átmegy a séma-ellenőrzésen, ezért ott a létezés-vizsgálat fut előbb: nem létező azonosítóra `404` a válasz, és csak létező erőforrásnál kapod meg a `400`-at.\n\nSzükséges scope: `contacts.write`.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Erőforrás-azonosító"},"required":true,"description":"Erőforrás-azonosító","name":"id","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"firstName":{"description":"Az új keresztnév. `null` vagy üres string küldésével a mező kiürül. A kulcs kihagyása érintetlenül hagyja."},"lastName":{"description":"Az új vezetéknév. `null` vagy üres string küldésével a mező kiürül. A kulcs kihagyása érintetlenül hagyja."},"email":{"description":"Az új e-mail cím. `null` vagy üres string küldésével a mező törlődik. Formátum-ellenőrzés nincs."},"phone":{"description":"Az új telefonszám. `null`, üres vagy csak szóközből álló string küldésével a mező törlődik. Formátum-ellenőrzés nincs, de a rendszer MINDEN szóközt eltávolít az értékből (`+36 30 123 4567` -> `+36301234567`), ezért a válaszban nem feltétlenül a küldött alakot kapod vissza."},"tags":{"type":"array","items":{"type":"string"},"description":"A címkék TELJES új listája - felülírja a meglévőket. FIGYELEM: ez az ág csak a kontakt címkemezőjét írja át. Az itt szereplő ÚJ címke NEM kerül be a fiók címkelistájába (nem jelenik meg a CRM szűrőjében és a címkekezelőben), és címkére kötött automatizmus SEM indul el tőle (nincs cél-értesítés, nincs `contact_tag_added` / `contact_tag_removed` esemény) - a `contact.updated` webhook viszont kimegy. Ha címkét adsz hozzá vagy veszel el, és számítasz ezekre a hatásokra, a `POST` / `DELETE /contacts/{id}/tags` végpontot használd: csak az regisztrálja a címkét és indítja el az automatizmusokat."},"customFields":{"type":"object","additionalProperties":{},"description":"Az egyedi mezők TELJES új készlete - felülírja a meglévőt. A törzsben nem szereplő kulcsok ELVESZNEK, üres objektummal (`{}`) mindet kiüríted. Egyetlen kulcs módosításához előbb olvasd ki a kontaktot (`GET /contacts/{id}`), a kapott `customFields` objektumot egészítsd ki, és azt küldd vissza egészben. Figyelem: a `POST /contacts` ettől ELTÉRŐEN viselkedik, ott a megadott kulcsok a meglévőkhöz fésülődnek."},"marketingConsent":{"type":"boolean","description":"A marketing hozzájárulás új értéke. Itt a `false` ténylegesen visszavonja a hozzájárulást. Nem logikai érték `400`-at ad."}}}}}},"responses":{"200":{"description":"Sikeres válasz","content":{"application/json":{"schema":{"type":"object","properties":{"contact":{"type":"object","properties":{"id":{"type":"string","description":"A kontakt állandó azonosítója. Ezt add át a `/contacts/{id}` alatti végpontoknak, és ez kerül a foglalások `contactId` mezőjébe is."},"firstName":{"type":"string","description":"Keresztnév. Ha nem ismert, üres string - sosem `null`."},"lastName":{"type":"string","description":"Vezetéknév. Ha nem ismert, üres string - sosem `null`."},"email":{"type":["string","null"],"description":"E-mail cím. `null`, ha nincs rögzítve. Az API-n létrehozott és módosított kontaktoknál kisbetűsítve tárolódik, a máshonnan (például CSV-import vagy a felület) bekerült címek viszont megőrizhetik az eredeti kis- és nagybetűket - dedupláláshoz és összevetéshez ezért mindig kisbetűsítve hasonlítsd össze. Az e-maillel EGYENRANGÚ összefésülési azonosító a telefonszám: az e-mail nem élvez elsőbbséget."},"phone":{"type":["string","null"],"description":"Telefonszám a tárolt, normalizált alakban: a rendszer rögzítéskor MINDEN szóközt eltávolít belőle, minden más karaktert (`+`, kötőjel, zárójel) érintetlenül hagy. A beküldött `+36 30 123 4567` értéket tehát `+36301234567` alakban kapod vissza. `null`, ha nincs. Az e-maillel egyenrangú összefésülési azonosító - nem csak akkor számít, ha az e-mail hiányzik."},"tags":{"type":"array","items":{"type":"string"},"description":"A kontakthoz rendelt címkék. Mindig tömb, címke nélküli kontaktnál üres. A sorrend nem garantált."},"source":{"type":"string","description":"Honnan került be a kontakt. Az API-n létrehozottak `api` értéket kapnak; a többi a keletkezés helyét jelöli (például `reservation`, `form`, `loyalty`, `website`, `import`, `manual`), a social inboxból érkezőkön pedig a platform neve áll (`facebook`, `instagram`). Szabad szöveg, nem rögzített enum - új forrás bármikor megjelenhet, ezért ismeretlen értékre is fel kell készülni."},"status":{"type":"string","description":"Az ügyfél-életciklus állapota. Négy értéket használ a rendszer: `active`, `inactive`, `vip` és `blocked`. A `blocked` üzletileg kötelező érvényű: az ilyen kontaktokat a rendszer kihagyja az e-mail- és WhatsApp-kampányok címzettjei közül, ezért ne kezeld `active`-ként. A mező az adatbázisban szabad szöveg, így örökölt vagy importált sorokon ettől eltérő érték is előfordulhat - ismeretlen értéket sose vegyél alapból aktívnak. Az API-n a mező nem írható; az itt létrehozott kontaktok `active` státuszt kapnak."},"customFields":{"type":"object","additionalProperties":{},"description":"A fiók egyedi kontaktmezői, mezőnév szerint. Az értékek típusa a mező típusától függ, ezért itt tetszőleges JSON érték állhat. Mindig objektum, üresen `{}`."},"marketingConsent":{"type":"boolean","description":"Van-e érvényes marketing hozzájárulás. `false`, ha nincs vagy visszavonták."},"createdAt":{"type":"string","format":"date-time","description":"A kontakt létrejöttének időpontja UTC-ben."},"updatedAt":{"type":"string","format":"date-time","description":"Az utolsó módosítás időpontja UTC-ben. Ezt szűri az `updatedSince` query-paraméter szinkronizáláshoz."}},"required":["id","firstName","lastName","email","phone","tags","source","status","customFields","marketingConsent","createdAt","updatedAt"]}},"required":["contact"]}}}},"400":{"description":"invalid_request: A séma-validáció bukott, vagy hiányzik egy kötelező paraméter. A `details[]` mezőnként sorolja fel az okot.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"401":{"description":"unauthorized: Hiányzó, hibás formátumú, ismeretlen, visszavont vagy lejárt token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"403":{"description":"forbidden: A token nem rendelkezik a szükséges scope-pal, a hívó IP nincs a kulcs allowlistáján, a fiók csomagja nem tartalmaz API-hozzáférést, vagy a fiók írás-tiltott (bemutató mód).","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"404":{"description":"not_found: Az erőforrás nem létezik EBBEN a fiókban. Egy másik fiókhoz tartozó azonosító is ezt adja - a kettő szándékosan megkülönböztethetetlen.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"429":{"description":"rate_limited: A percalapú sebességkorlát (alapból 120 kérés/perc/kulcs) túllépve.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"500":{"description":"internal_error: Váratlan szerverhiba. Egyetlen végponton (`POST /contacts`) ugyanez a hiba a rövidebb `internal` kóddal érkezik - kezeld a kettőt azonosan.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}}}}},"/contacts/{id}/notes":{"post":{"operationId":"contacts.notes_create","tags":["contacts"],"summary":"Jegyzet hozzáfűzése","description":"Új, önálló jegyzetet fűz a kontakthoz, szerzővel és időbélyeggel. A meglévő jegyzeteket nem érinti, és nincs mód meglévő jegyzet módosítására vagy törlésére. HOL JELENIK MEG: a kontakt saját adatlapjának `Megjegyzések` fülén (ott a felületen szerkeszthető és törölhető is), valamint a mobil nézet kontakt-idővonalán. NEM jelenik meg a Kapcsolatok listából nyíló gyorsnézet `Jegyzetek` fülén, és az `Aktivitás` idővonalra sem kerül fel - ha ott keresed, hiányzónak tűnik, pedig a jegyzet elmentődött, és a `GET /contacts/{id}/notes` vissza is adja. Ez a jegyzet a `POST /contacts` `note` mezőjétől teljesen független: a kettő két külön helyre kerül, és nincs köztük átjárás. Ha a törzs SÉMAILAG érvénytelen (rossz típus, ismeretlen enum-érték) ÉS az `{id}` sem létezik, a válasz `400`, nem `404` - a séma-ellenőrzés megelőzi a létezés-vizsgálatot, hogy egy formailag hibás kérés hívója se kapjon jelzést az erőforrás létezéséről. A sémailag ÉRVÉNYES, de üres `{}` törzs viszont átmegy a séma-ellenőrzésen, ezért ott a létezés-vizsgálat fut előbb: nem létező azonosítóra `404` a válasz, és csak létező erőforrásnál kapod meg a `400`-at.\n\nSzükséges scope: `contacts.write`.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Erőforrás-azonosító"},"required":true,"description":"Erőforrás-azonosító","name":"id","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"content":{"type":"string","minLength":1,"description":"A jegyzet szövege. A szélső szóközök levágódnak, a csak szóközből álló érték üresnek számít. 5000 karakter felett a szöveg CSENDBEN levágódik - a kérés nem hibázik, ezért a hosszt neked kell figyelned."},"author":{"type":"string","description":"Ki írta a jegyzetet. Elhagyva vagy üresen a szerző `API` lesz. 100 karakter felett csendben levágódik."}},"required":["content"]}}}},"responses":{"201":{"description":"Sikeres válasz","content":{"application/json":{"schema":{"type":"object","properties":{"note":{"type":"object","properties":{"id":{"type":"string","description":"A jegyzet azonosítója."},"content":{"type":"string","description":"A jegyzet szövege."},"staffName":{"type":["string","null"],"description":"Ki írta a jegyzetet. Az API-n keresztül létrehozottaknál a küldött szerzőnév, megadás híján `API`."},"createdAt":{"type":"string","format":"date-time","description":"A jegyzet keletkezésének időpontja UTC-ben."}},"required":["id","content","staffName","createdAt"]}},"required":["note"]}}}},"400":{"description":"invalid_request: A séma-validáció bukott, vagy hiányzik egy kötelező paraméter. A `details[]` mezőnként sorolja fel az okot.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"401":{"description":"unauthorized: Hiányzó, hibás formátumú, ismeretlen, visszavont vagy lejárt token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"403":{"description":"forbidden: A token nem rendelkezik a szükséges scope-pal, a hívó IP nincs a kulcs allowlistáján, a fiók csomagja nem tartalmaz API-hozzáférést, vagy a fiók írás-tiltott (bemutató mód).","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"404":{"description":"not_found: Az erőforrás nem létezik EBBEN a fiókban. Egy másik fiókhoz tartozó azonosító is ezt adja - a kettő szándékosan megkülönböztethetetlen.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"429":{"description":"rate_limited: A percalapú sebességkorlát (alapból 120 kérés/perc/kulcs) túllépve.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"500":{"description":"internal_error: Váratlan szerverhiba. Egyetlen végponton (`POST /contacts`) ugyanez a hiba a rövidebb `internal` kóddal érkezik - kezeld a kettőt azonosan.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}}}},"get":{"operationId":"contacts.notes_list","tags":["contacts"],"summary":"Kontakt jegyzeteinek listázása","description":"A kontakthoz tartozó jegyzetek, a legfrissebbel kezdve. Ezek önálló jegyzet-bejegyzések, szerzővel és időbélyeggel: a `POST /contacts/{id}/notes` végponttal, illetve a kezelőfelületen rögzített jegyzetek. A felületen ugyanezt a kontakt saját adatlapjának `Megjegyzések` fülén és a mobil nézet kontakt-idővonalán látod. A Kapcsolatok listából nyíló gyorsnézet `Jegyzetek` füle EZEKET NEM mutatja: az a kontakt szabad szöveges jegyzetmezőjét jeleníti meg, amelybe a `POST /contacts` `note` mezője ír - az ott küldött szöveg ebben a listában soha nem jelenik meg. Ez a végpont nem lapozható: csak `limit` szerinti korlátozást fogad, `offset` sem a kérésben, sem a válaszban nincs. A régebbi jegyzetekhez emeld a `limit` értékét.\n\nSzükséges scope: `contacts.readonly`.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Erőforrás-azonosító"},"required":true,"description":"Erőforrás-azonosító","name":"id","in":"path"},{"schema":{"type":"integer","minimum":1,"maximum":200,"default":50,"description":"Hány jegyzet jöjjön vissza, a legfrissebbtől számolva."},"required":false,"description":"Hány jegyzet jöjjön vissza, a legfrissebbtől számolva.","name":"limit","in":"query"}],"responses":{"200":{"description":"Sikeres válasz","content":{"application/json":{"schema":{"type":"object","properties":{"notes":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"A jegyzet azonosítója."},"content":{"type":"string","description":"A jegyzet szövege."},"staffName":{"type":["string","null"],"description":"Ki írta a jegyzetet. Az API-n keresztül létrehozottaknál a küldött szerzőnév, megadás híján `API`."},"createdAt":{"type":"string","format":"date-time","description":"A jegyzet keletkezésének időpontja UTC-ben."}},"required":["id","content","staffName","createdAt"]},"description":"A jegyzetek, keletkezés szerint csökkenő sorrendben."}},"required":["notes"]}}}},"400":{"description":"invalid_request: A séma-validáció bukott, vagy hiányzik egy kötelező paraméter. A `details[]` mezőnként sorolja fel az okot.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"401":{"description":"unauthorized: Hiányzó, hibás formátumú, ismeretlen, visszavont vagy lejárt token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"403":{"description":"forbidden: A token nem rendelkezik a szükséges scope-pal, a hívó IP nincs a kulcs allowlistáján, a fiók csomagja nem tartalmaz API-hozzáférést, vagy a fiók írás-tiltott (bemutató mód).","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"404":{"description":"not_found: Az erőforrás nem létezik EBBEN a fiókban. Egy másik fiókhoz tartozó azonosító is ezt adja - a kettő szándékosan megkülönböztethetetlen.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"429":{"description":"rate_limited: A percalapú sebességkorlát (alapból 120 kérés/perc/kulcs) túllépve.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"500":{"description":"internal_error: Váratlan szerverhiba. Egyetlen végponton (`POST /contacts`) ugyanez a hiba a rövidebb `internal` kóddal érkezik - kezeld a kettőt azonosan.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}}}}},"/contacts/{id}/tags":{"post":{"operationId":"contacts.tags_add","tags":["contacts"],"summary":"Címkék hozzáadása (unió)","description":"A megadott címkéket hozzáadja a kontakt meglévő címkéihez. A meglévők megmaradnak, a duplikátumok kiszűrődnek. Csak ez a végpont regisztrálja az új címkét a fiók címkelistájába, és csak ez indít címke-alapú automatizmust. Ha a teljes listát akarod felülírni, a `PATCH /contacts/{id}` `tags` mezőjét használd - de az a felülírás nem regisztrál új címkét és nem indít címke-automatizmust. Ha a törzs SÉMAILAG érvénytelen (rossz típus, ismeretlen enum-érték) ÉS az `{id}` sem létezik, a válasz `400`, nem `404` - a séma-ellenőrzés megelőzi a létezés-vizsgálatot, hogy egy formailag hibás kérés hívója se kapjon jelzést az erőforrás létezéséről. A sémailag ÉRVÉNYES, de üres `{}` törzs viszont átmegy a séma-ellenőrzésen, ezért ott a létezés-vizsgálat fut előbb: nem létező azonosítóra `404` a válasz, és csak létező erőforrásnál kapod meg a `400`-at.\n\nSzükséges scope: `contacts.write`.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Erőforrás-azonosító"},"required":true,"description":"Erőforrás-azonosító","name":"id","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"tags":{"type":"array","items":{},"description":"A hozzáadandó címkék. A szélső szóközök levágódnak, az ismétlődések összevonódnak."}},"required":["tags"]}}}},"responses":{"200":{"description":"Sikeres válasz","content":{"application/json":{"schema":{"type":"object","properties":{"contact":{"type":"object","properties":{"id":{"type":"string","description":"A kontakt állandó azonosítója. Ezt add át a `/contacts/{id}` alatti végpontoknak, és ez kerül a foglalások `contactId` mezőjébe is."},"firstName":{"type":"string","description":"Keresztnév. Ha nem ismert, üres string - sosem `null`."},"lastName":{"type":"string","description":"Vezetéknév. Ha nem ismert, üres string - sosem `null`."},"email":{"type":["string","null"],"description":"E-mail cím. `null`, ha nincs rögzítve. Az API-n létrehozott és módosított kontaktoknál kisbetűsítve tárolódik, a máshonnan (például CSV-import vagy a felület) bekerült címek viszont megőrizhetik az eredeti kis- és nagybetűket - dedupláláshoz és összevetéshez ezért mindig kisbetűsítve hasonlítsd össze. Az e-maillel EGYENRANGÚ összefésülési azonosító a telefonszám: az e-mail nem élvez elsőbbséget."},"phone":{"type":["string","null"],"description":"Telefonszám a tárolt, normalizált alakban: a rendszer rögzítéskor MINDEN szóközt eltávolít belőle, minden más karaktert (`+`, kötőjel, zárójel) érintetlenül hagy. A beküldött `+36 30 123 4567` értéket tehát `+36301234567` alakban kapod vissza. `null`, ha nincs. Az e-maillel egyenrangú összefésülési azonosító - nem csak akkor számít, ha az e-mail hiányzik."},"tags":{"type":"array","items":{"type":"string"},"description":"A kontakthoz rendelt címkék. Mindig tömb, címke nélküli kontaktnál üres. A sorrend nem garantált."},"source":{"type":"string","description":"Honnan került be a kontakt. Az API-n létrehozottak `api` értéket kapnak; a többi a keletkezés helyét jelöli (például `reservation`, `form`, `loyalty`, `website`, `import`, `manual`), a social inboxból érkezőkön pedig a platform neve áll (`facebook`, `instagram`). Szabad szöveg, nem rögzített enum - új forrás bármikor megjelenhet, ezért ismeretlen értékre is fel kell készülni."},"status":{"type":"string","description":"Az ügyfél-életciklus állapota. Négy értéket használ a rendszer: `active`, `inactive`, `vip` és `blocked`. A `blocked` üzletileg kötelező érvényű: az ilyen kontaktokat a rendszer kihagyja az e-mail- és WhatsApp-kampányok címzettjei közül, ezért ne kezeld `active`-ként. A mező az adatbázisban szabad szöveg, így örökölt vagy importált sorokon ettől eltérő érték is előfordulhat - ismeretlen értéket sose vegyél alapból aktívnak. Az API-n a mező nem írható; az itt létrehozott kontaktok `active` státuszt kapnak."},"customFields":{"type":"object","additionalProperties":{},"description":"A fiók egyedi kontaktmezői, mezőnév szerint. Az értékek típusa a mező típusától függ, ezért itt tetszőleges JSON érték állhat. Mindig objektum, üresen `{}`."},"marketingConsent":{"type":"boolean","description":"Van-e érvényes marketing hozzájárulás. `false`, ha nincs vagy visszavonták."},"createdAt":{"type":"string","format":"date-time","description":"A kontakt létrejöttének időpontja UTC-ben."},"updatedAt":{"type":"string","format":"date-time","description":"Az utolsó módosítás időpontja UTC-ben. Ezt szűri az `updatedSince` query-paraméter szinkronizáláshoz."}},"required":["id","firstName","lastName","email","phone","tags","source","status","customFields","marketingConsent","createdAt","updatedAt"]},"added":{"type":"array","items":{"type":"string"},"description":"Azok a címkék, amik ténylegesen ÚJKÉNT kerültek fel. A már meglévők nincsenek benne, tehát ez a tömb üres is lehet."}},"required":["contact","added"]}}}},"400":{"description":"invalid_request: A séma-validáció bukott, vagy hiányzik egy kötelező paraméter. A `details[]` mezőnként sorolja fel az okot.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"401":{"description":"unauthorized: Hiányzó, hibás formátumú, ismeretlen, visszavont vagy lejárt token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"403":{"description":"forbidden: A token nem rendelkezik a szükséges scope-pal, a hívó IP nincs a kulcs allowlistáján, a fiók csomagja nem tartalmaz API-hozzáférést, vagy a fiók írás-tiltott (bemutató mód).","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"404":{"description":"not_found: Az erőforrás nem létezik EBBEN a fiókban. Egy másik fiókhoz tartozó azonosító is ezt adja - a kettő szándékosan megkülönböztethetetlen.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"429":{"description":"rate_limited: A percalapú sebességkorlát (alapból 120 kérés/perc/kulcs) túllépve.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"500":{"description":"internal_error: Váratlan szerverhiba. Egyetlen végponton (`POST /contacts`) ugyanez a hiba a rövidebb `internal` kóddal érkezik - kezeld a kettőt azonosan.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}}}},"delete":{"operationId":"contacts.tags_remove","tags":["contacts"],"summary":"Címkék eltávolítása","description":"A DELETE kérés törzse (`{ \"tags\": [...] }`) kötelező - a route ténylegesen JSON body-t olvas DELETE-nél is. Ha a törzs SÉMAILAG érvénytelen (rossz típus, ismeretlen enum-érték) ÉS az `{id}` sem létezik, a válasz `400`, nem `404` - a séma-ellenőrzés megelőzi a létezés-vizsgálatot, hogy egy formailag hibás kérés hívója se kapjon jelzést az erőforrás létezéséről. A sémailag ÉRVÉNYES, de üres `{}` törzs viszont átmegy a séma-ellenőrzésen, ezért ott a létezés-vizsgálat fut előbb: nem létező azonosítóra `404` a válasz, és csak létező erőforrásnál kapod meg a `400`-at.\n\nSzükséges scope: `contacts.write`.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Erőforrás-azonosító"},"required":true,"description":"Erőforrás-azonosító","name":"id","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"tags":{"type":"array","items":{},"description":"Az eltávolítandó címkék. A kontakton nem szereplő címke megadása nem hiba, egyszerűen nem történik vele semmi."}},"required":["tags"]}}}},"responses":{"200":{"description":"Sikeres válasz","content":{"application/json":{"schema":{"type":"object","properties":{"contact":{"type":"object","properties":{"id":{"type":"string","description":"A kontakt állandó azonosítója. Ezt add át a `/contacts/{id}` alatti végpontoknak, és ez kerül a foglalások `contactId` mezőjébe is."},"firstName":{"type":"string","description":"Keresztnév. Ha nem ismert, üres string - sosem `null`."},"lastName":{"type":"string","description":"Vezetéknév. Ha nem ismert, üres string - sosem `null`."},"email":{"type":["string","null"],"description":"E-mail cím. `null`, ha nincs rögzítve. Az API-n létrehozott és módosított kontaktoknál kisbetűsítve tárolódik, a máshonnan (például CSV-import vagy a felület) bekerült címek viszont megőrizhetik az eredeti kis- és nagybetűket - dedupláláshoz és összevetéshez ezért mindig kisbetűsítve hasonlítsd össze. Az e-maillel EGYENRANGÚ összefésülési azonosító a telefonszám: az e-mail nem élvez elsőbbséget."},"phone":{"type":["string","null"],"description":"Telefonszám a tárolt, normalizált alakban: a rendszer rögzítéskor MINDEN szóközt eltávolít belőle, minden más karaktert (`+`, kötőjel, zárójel) érintetlenül hagy. A beküldött `+36 30 123 4567` értéket tehát `+36301234567` alakban kapod vissza. `null`, ha nincs. Az e-maillel egyenrangú összefésülési azonosító - nem csak akkor számít, ha az e-mail hiányzik."},"tags":{"type":"array","items":{"type":"string"},"description":"A kontakthoz rendelt címkék. Mindig tömb, címke nélküli kontaktnál üres. A sorrend nem garantált."},"source":{"type":"string","description":"Honnan került be a kontakt. Az API-n létrehozottak `api` értéket kapnak; a többi a keletkezés helyét jelöli (például `reservation`, `form`, `loyalty`, `website`, `import`, `manual`), a social inboxból érkezőkön pedig a platform neve áll (`facebook`, `instagram`). Szabad szöveg, nem rögzített enum - új forrás bármikor megjelenhet, ezért ismeretlen értékre is fel kell készülni."},"status":{"type":"string","description":"Az ügyfél-életciklus állapota. Négy értéket használ a rendszer: `active`, `inactive`, `vip` és `blocked`. A `blocked` üzletileg kötelező érvényű: az ilyen kontaktokat a rendszer kihagyja az e-mail- és WhatsApp-kampányok címzettjei közül, ezért ne kezeld `active`-ként. A mező az adatbázisban szabad szöveg, így örökölt vagy importált sorokon ettől eltérő érték is előfordulhat - ismeretlen értéket sose vegyél alapból aktívnak. Az API-n a mező nem írható; az itt létrehozott kontaktok `active` státuszt kapnak."},"customFields":{"type":"object","additionalProperties":{},"description":"A fiók egyedi kontaktmezői, mezőnév szerint. Az értékek típusa a mező típusától függ, ezért itt tetszőleges JSON érték állhat. Mindig objektum, üresen `{}`."},"marketingConsent":{"type":"boolean","description":"Van-e érvényes marketing hozzájárulás. `false`, ha nincs vagy visszavonták."},"createdAt":{"type":"string","format":"date-time","description":"A kontakt létrejöttének időpontja UTC-ben."},"updatedAt":{"type":"string","format":"date-time","description":"Az utolsó módosítás időpontja UTC-ben. Ezt szűri az `updatedSince` query-paraméter szinkronizáláshoz."}},"required":["id","firstName","lastName","email","phone","tags","source","status","customFields","marketingConsent","createdAt","updatedAt"]},"removed":{"type":"array","items":{"type":"string"},"description":"Azok a címkék, amik ténylegesen le is kerültek. A kontakton nem szereplő címkék nincsenek benne."}},"required":["contact","removed"]}}}},"400":{"description":"invalid_request: A séma-validáció bukott, vagy hiányzik egy kötelező paraméter. A `details[]` mezőnként sorolja fel az okot.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"401":{"description":"unauthorized: Hiányzó, hibás formátumú, ismeretlen, visszavont vagy lejárt token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"403":{"description":"forbidden: A token nem rendelkezik a szükséges scope-pal, a hívó IP nincs a kulcs allowlistáján, a fiók csomagja nem tartalmaz API-hozzáférést, vagy a fiók írás-tiltott (bemutató mód).","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"404":{"description":"not_found: Az erőforrás nem létezik EBBEN a fiókban. Egy másik fiókhoz tartozó azonosító is ezt adja - a kettő szándékosan megkülönböztethetetlen.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"429":{"description":"rate_limited: A percalapú sebességkorlát (alapból 120 kérés/perc/kulcs) túllépve.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"500":{"description":"internal_error: Váratlan szerverhiba. Egyetlen végponton (`POST /contacts`) ugyanez a hiba a rövidebb `internal` kóddal érkezik - kezeld a kettőt azonosan.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}}}}},"/pipelines":{"get":{"operationId":"pipelines.list","tags":["pipelines"],"summary":"Pipeline-ok listázása szakaszokkal","description":"A fiók összes CRM pipeline-ja, mindegyiknél a szakaszokkal. Ez a kereső táblázat a `deals` végpontok `pipelineId` és `stageId` mezőihez: az azonosítók itt derülnek ki. A lista nem lapozható, és `deals.readonly` scope kell hozzá. Gyorsítótárazható, de nem örökre: a szakaszokat a felületen bármikor átnevezik, átrendezik vagy törlik, a válasz pedig nem hordoz sem verziót, sem módosítási időpontot, ezért az eltett listát rendszeresen - például naponta - kérd le újra.\n\nSzükséges scope: `deals.readonly`.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Sikeres válasz","content":{"application/json":{"schema":{"type":"object","properties":{"pipelines":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"A pipeline azonosítója. Ezt add meg üzlet létrehozásakor a `pipelineId` mezőben."},"name":{"type":"string","description":"A pipeline neve, ahogy a felületen megjelenik."},"type":{"type":["string","null"],"description":"A pipeline besorolása. Az alkalmazás hat rögzített értéket ad: `sales`, `onboarding`, `support`, `catering`, `events`, `custom`; ismeretlen bemenet csendben `custom`-ra esik vissza, ezért a felületen létrehozott pipeline-nak mindig van besorolása. `null` csak régi vagy importált soron fordulhat elő."},"stages":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"A szakasz azonosítója. Ezt add meg a `stageId` mezőben üzlet létrehozásakor vagy szakaszváltáskor."},"name":{"type":"string","description":"A szakasz tárolt neve. Az API a fiókban rögzített értéket adja vissza változatlanul: régi, még nem szerkesztett pipeline-oknál ez lehet üres string, sőt a kulcs hiányozhat is - a felület ilyenkor helyettesítő nevet (`Fázis 1`, `Fázis 2`) mutat, tehát a két érték eltérhet. Ezért szerepel a mező OPCIONÁLISKÉNT: a kezelőfelület olvasáskor kijavítja a hiányzó nevet, az API viszont a tárolt értéket adja vissza érintetlenül."}},"required":["id"],"description":"Egy szakasz a pipeline-on belül. Az `id` és a `name` mellett a szakasz további, a szerződésben nem rögzített kulcsokat is visszaad: `color` (hex színkód), `sortOrder` (0-tól induló sorszám), és ha a fiók beállított ilyet, `autoActions` - a szakaszhoz kötött automatizmusok, amelyek belső azonosítókra (felhasználó-azonosító, workflow-azonosító) és e-mail beállításokra hivatkozhatnak. Ezek a kulcsok nincsenek adatbázis-szinten kikényszerítve, régi soron hiányozhatnak, és a jövőben változhatnak - ne építs rájuk integrációt."},"description":"A pipeline szakaszai a tárolt sorrendjükben. A felület a szakaszok `sortOrder` értéke szerint rendez, tehát ha a kettő eltérne, a `sortOrder` az irányadó."},"isDefault":{"type":"boolean","description":"`true`, ha a fiók ezt jelölte meg alapértelmezett pipeline-nak. Nem garantált, hogy pontosan egy ilyen van: előfordul, hogy egyik pipeline sem alapértelmezett (a jelölés a felületen levehető, az alapértelmezett pipeline törlésekor pedig a fiók nem kap újat), beállítás közben pedig rövid ideig kettő is lehet `true`. Ha nem tudod, melyik pipeline-ba tegyél egy üzletet, az első `isDefault: true` elemet válaszd, ha pedig nincs ilyen, a lista első elemét."},"createdAt":{"type":"string","format":"date-time","description":"A pipeline létrejöttének időpontja UTC-ben."}},"required":["id","name","type","stages","isDefault","createdAt"]},"description":"A fiók pipeline-jai, létrehozási idő szerint növekvő sorrendben. Üres tömb, ha a fiókban még nincs pipeline: a rendszer egyet sem hoz létre automatikusan, tehát a CRM-et nem használó vagy frissen létrehozott fióknál az üres lista a szabályos válasz. Üzlet létrehozása előtt ellenőrizd, hogy van-e elem a tömbben."}},"required":["pipelines"]}}}},"401":{"description":"unauthorized: Hiányzó, hibás formátumú, ismeretlen, visszavont vagy lejárt token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"403":{"description":"forbidden: A token nem rendelkezik a szükséges scope-pal, a hívó IP nincs a kulcs allowlistáján, a fiók csomagja nem tartalmaz API-hozzáférést, vagy a fiók írás-tiltott (bemutató mód).","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"429":{"description":"rate_limited: A percalapú sebességkorlát (alapból 120 kérés/perc/kulcs) túllépve.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"500":{"description":"internal_error: Váratlan szerverhiba. Egyetlen végponton (`POST /contacts`) ugyanez a hiba a rövidebb `internal` kóddal érkezik - kezeld a kettőt azonosan.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}}}}},"/deals":{"post":{"operationId":"deals.create","tags":["deals"],"summary":"Üzlet létrehozása","description":"Új üzletet nyit a megadott pipeline-ban. Az üzlet állapota mindig `open` lesz - a kérésből nem állítható, a lezáráshoz a `PATCH /deals/{id}` végpontot használd. A hívás idempotens: `Idempotency-Key` fejléccel az újrapróbálkozás nem hoz létre második üzletet. A `stageId` annak a pipeline-nak a szakasza kell legyen, amit a `pipelineId` megnevez - más pipeline szakaszára `400` a válasz. Szakasz nélküli pipeline-ba szintén nem lehet üzletet nyitni.\n\nSzükséges scope: `deals.write`.\n\nTámogatja az `Idempotency-Key` fejlécet.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string","minLength":1,"description":"Az üzlet megnevezése. A szélső szóközök levágódnak, a csak szóközből álló érték üresnek számít."},"pipelineId":{"type":"string","minLength":1,"maxLength":128,"description":"Melyik pipeline-ba kerüljön. Az elérhető pipeline-okat a `GET /pipelines` adja; ismeretlen azonosítóra `404` a válasz."},"stageId":{"type":"string","minLength":1,"maxLength":128,"description":"A kezdő szakasz. Elhagyva a pipeline első szakaszába kerül az üzlet."},"value":{"type":"number","minimum":0,"description":"Az üzlet értéke egész forintban (nem fillérben). Nem lehet negatív. Törtszámot ne küldj: az API nem kerekít, az érték változtatás nélkül kerül az adatbázis egész típusú oszlopába, ezért a tizedes érték a mentést szerverhibára (`500`) futtathatja. `Infinity` és `NaN` nem érvényes."},"currency":{"description":"Az érték pénzneme. `HUF` lesz, ha a kulcsot elhagyod, ha csak szóközből álló stringet küldesz, VAGY ha nem stringet küldesz (szám, `null`, objektum, tömb) - ez utóbbi sem ad `400`-at, csendben `HUF`-ra esik vissza. Minden más stringet az API ellenőrzés nélkül, a szélső szóközök levágásával tárol el: nincs ISO-4217 lista és nincs hosszellenőrzés, tehát az érvényes pénznemkód küldése a hívó felelőssége. Az érték utólag nem módosítható, a `PATCH /deals/{id}` nem kezel `currency` mezőt."},"description":{"type":"string","description":"Szabad szöveges leírás. Hosszkorlát nincs."},"tags":{"type":"array","items":{"type":"string"},"description":"Címkék az üzlethez."},"contactId":{"type":"string","minLength":1,"maxLength":128,"description":"Meglévő kontakt hozzákötése. Ilyenkor a kontakt neve, e-mail címe és telefonszáma pillanatfelvételként rámásolódik az üzletre, és a válaszban is látszik. Ez a másolat később nem frissül: sem a kontakt átnevezése, sem a `PATCH /deals/{id}` nem írja át."}},"required":["title","pipelineId"]}}}},"responses":{"201":{"description":"Sikeres válasz","content":{"application/json":{"schema":{"type":"object","properties":{"deal":{"type":"object","properties":{"id":{"type":"string","description":"Az üzlet állandó azonosítója."},"pipelineId":{"type":"string","description":"Melyik pipeline-ban van az üzlet. A pipeline-okat a `GET /pipelines` listázza."},"stageId":{"type":"string","description":"Az aktuális szakasz azonosítója a pipeline-on belül. A szakaszok nevét és sorrendjét a `GET /pipelines` adja."},"title":{"type":"string","description":"Az üzlet megnevezése."},"value":{"type":"integer","description":"Az üzlet értéke egész forintban (nem fillérben). Ha nem adtak meg értéket, `0`."},"currency":{"type":"string","description":"Az érték pénzneme. Alapértelmezés `HUF`. Az API azt az értéket adja vissza, amit létrehozáskor kapott, szó szerint: nincs ISO-4217 ellenőrzés és nincs hosszkorlát, ezért ne feltételezd, hogy a mező három karakter."},"status":{"type":"string","description":"Az üzlet állapota. A Dynex felülete és ez az API ezt a négy értéket állítja be: `open` (nyitott), `won` (megnyert), `lost` (elveszített), `abandoned` (elejtett). Az adatbázisban viszont szabad szöveg, ezért egy régebbi vagy migrált sor ettől eltérőt is hordozhat: ne írj kimerítő elágazást a négy értékre, az ismeretlen státuszt is kezeld. Ilyen sor a lista `status` szűrőjével nem kérdezhető le, mert az csak a négy felsorolt értéket fogadja el."},"contactId":{"type":["string","null"],"description":"A kapcsolódó kontakt azonosítója, ha az üzlet CRM-kontakthoz van kötve. `null`, ha nincs kontakt kötve. A kontakt törlése után a mező megbízhatatlan: az API-n létrehozott üzletnél a kötés leválik és `null` lesz, miközben a `contactName`, `contactEmail` és `contactPhone` a korábban rámásolt értékkel megmarad - kitöltött kontaktnév melletti `null` azonosító tehát törölt kontaktot is jelenthet, nem csak azt, hogy sosem volt kötve. Régebbi üzleteknél a fordítottja is előfordulhat: az azonosító megmarad, de a `GET /contacts/{id}` már `404`-et ad rá. Ha élő kontaktra van szükséged, mindig ellenőrizd a `GET /contacts/{id}` végponttal."},"contactName":{"type":["string","null"],"description":"A kapcsolódó kontakt neve az üzlet létrehozásának pillanatában - pillanatfelvétel, nem élő hivatkozás. Ezen az API-n később NEM frissíthető: a `PATCH /deals/{id}` nem nyúl ehhez a mezőhöz, és `contactId`-t sem fogad. A kontakt átnevezése nem írja át visszamenőleg; a mindenkori aktuális névhez a `contactId` alapján a `GET /contacts/{id}` végpontot hívd."},"contactEmail":{"type":["string","null"],"description":"A kapcsolódó kontakt e-mail címe, az üzlet létrehozásakor rámásolva. Ezen az API-n később nem frissül - az aktuális értékhez a `GET /contacts/{id}` végpontot hívd."},"contactPhone":{"type":["string","null"],"description":"A kapcsolódó kontakt telefonszáma, az üzlet létrehozásakor rámásolva. Ezen az API-n később nem frissül - az aktuális értékhez a `GET /contacts/{id}` végpontot hívd."},"description":{"type":["string","null"],"description":"Szabad szöveges leírás az üzletről."},"tags":{"type":"array","items":{"type":"string"},"description":"Az üzlet címkéi. Mindig tömb, üresen `[]`."},"priority":{"type":["string","null"],"description":"Prioritás a fiók saját besorolása szerint (jellemzően `low`, `medium`, `high`). Ezen az API-n nem állítható és nem törölhető: sem a `POST /deals`, sem a `PATCH /deals/{id}` nem fogad `priority` mezőt, ezért az API-n létrehozott üzletnél mindig `null`. Értéket csak a Dynex felületén kaphat, ahol az új üzlet alapértéke `medium`."},"expectedCloseDate":{"type":["string","null"],"format":"date-time","description":"A várható lezárás tervezett időpontja UTC-ben. Ezen az API-n nem állítható és nem törölhető: sem a `POST /deals`, sem a `PATCH /deals/{id}` nem fogad `expectedCloseDate` mezőt, ezért az API-n létrehozott üzletnél mindig `null`. Értéket csak a Dynex felületén kaphat."},"closedAt":{"type":["string","null"],"format":"date-time","description":"A tényleges lezárás időpontja UTC-ben. Akkor telik meg, amikor az üzlet bármely nem `open` állapotba kerül: `won`, `lost` és `abandoned` esetén egyaránt, ezért a lezárás MÓDJÁRA ne ebből, hanem a `status` mezőből következtess. Ha az üzlet `open` állapotra vált vissza, a mező `null`-ra törlődik, és a korábbi lezárási időpont véglegesen elvész - a rendszer sehol nem őrzi meg."},"lostReason":{"type":["string","null"],"description":"Az elvesztés oka. Csak akkor íródik, amikor egy `PATCH /deals/{id}` a `status` mezőt `lost` értékre állítja. A későbbi állapotváltás nem törli, ezért egy újranyitott (`open`) vagy megnyert üzleten is ott maradhat a korábban rögzített ok - a jelenlegi állapotot a `status` mondja meg."},"createdAt":{"type":"string","format":"date-time","description":"Az üzlet létrejöttének időpontja UTC-ben."},"updatedAt":{"type":"string","format":"date-time","description":"Az utolsó módosítás időpontja UTC-ben."}},"required":["id","pipelineId","stageId","title","value","currency","status","contactId","contactName","contactEmail","contactPhone","description","tags","priority","expectedCloseDate","closedAt","lostReason","createdAt","updatedAt"]}},"required":["deal"]}}}},"400":{"description":"invalid_request: A séma-validáció bukott, vagy hiányzik egy kötelező paraméter. A `details[]` mezőnként sorolja fel az okot.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"401":{"description":"unauthorized: Hiányzó, hibás formátumú, ismeretlen, visszavont vagy lejárt token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"403":{"description":"forbidden: A token nem rendelkezik a szükséges scope-pal, a hívó IP nincs a kulcs allowlistáján, a fiók csomagja nem tartalmaz API-hozzáférést, vagy a fiók írás-tiltott (bemutató mód).","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"404":{"description":"not_found: Az erőforrás nem létezik EBBEN a fiókban. Egy másik fiókhoz tartozó azonosító is ezt adja - a kettő szándékosan megkülönböztethetetlen.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"429":{"description":"rate_limited: A percalapú sebességkorlát (alapból 120 kérés/perc/kulcs) túllépve.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"500":{"description":"internal_error: Váratlan szerverhiba. Egyetlen végponton (`POST /contacts`) ugyanez a hiba a rövidebb `internal` kóddal érkezik - kezeld a kettőt azonosan.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}}}},"get":{"operationId":"deals.list","tags":["deals"],"summary":"Üzletek listázása","description":"Lapozott lista a fiók üzleteiről, a legutóbb létrehozottal kezdve. A szűrők ÉS kapcsolattal érvényesülnek. A szakaszok nevéhez és sorrendjéhez a `GET /pipelines` végpontot hívd le egyszer, és a `stageId` értékeket ahhoz párosítsd.\n\nSzükséges scope: `deals.readonly`.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","minLength":1,"maxLength":128,"description":"Csak ennek a pipeline-nak az üzletei."},"required":false,"description":"Csak ennek a pipeline-nak az üzletei.","name":"pipelineId","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":128,"description":"Csak az ebben a szakaszban álló üzletek. Önmagában is használható, `pipelineId` nélkül."},"required":false,"description":"Csak az ebben a szakaszban álló üzletek. Önmagában is használható, `pipelineId` nélkül.","name":"stageId","in":"query"},{"schema":{"type":"string","enum":["open","won","lost","abandoned"],"description":"Szűrés állapotra. `open`: nyitott. `won`: megnyert. `lost`: elveszített. `abandoned`: elejtett."},"required":false,"description":"Szűrés állapotra. `open`: nyitott. `won`: megnyert. `lost`: elveszített. `abandoned`: elejtett.","name":"status","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":128,"description":"Csak az ehhez a kontakthoz kötött üzletek. A kontakt törlése után az API-n létrehozott üzletek kiesnek ebből a szűrőből, akkor is, ha a `contactName` még ki van töltve."},"required":false,"description":"Csak az ehhez a kontakthoz kötött üzletek. A kontakt törlése után az API-n létrehozott üzletek kiesnek ebből a szűrőből, akkor is, ha a `contactName` még ki van töltve.","name":"contactId","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":200,"default":50,"description":"Találatok maximális száma (1-200, alapértelmezés 50; a tartományon kívüli érték a határra szorítódik, nem hibát ad)"},"required":false,"description":"Találatok maximális száma (1-200, alapértelmezés 50; a tartományon kívüli érték a határra szorítódik, nem hibát ad)","name":"limit","in":"query"},{"schema":{"type":"integer","minimum":0,"maximum":1000000,"default":0,"description":"Hány találatot ugorjon át (a tartományon kívüli érték a határra szorítódik, nem hibát ad)"},"required":false,"description":"Hány találatot ugorjon át (a tartományon kívüli érték a határra szorítódik, nem hibát ad)","name":"offset","in":"query"}],"responses":{"200":{"description":"Sikeres válasz","content":{"application/json":{"schema":{"type":"object","properties":{"deals":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Az üzlet állandó azonosítója."},"pipelineId":{"type":"string","description":"Melyik pipeline-ban van az üzlet. A pipeline-okat a `GET /pipelines` listázza."},"stageId":{"type":"string","description":"Az aktuális szakasz azonosítója a pipeline-on belül. A szakaszok nevét és sorrendjét a `GET /pipelines` adja."},"title":{"type":"string","description":"Az üzlet megnevezése."},"value":{"type":"integer","description":"Az üzlet értéke egész forintban (nem fillérben). Ha nem adtak meg értéket, `0`."},"currency":{"type":"string","description":"Az érték pénzneme. Alapértelmezés `HUF`. Az API azt az értéket adja vissza, amit létrehozáskor kapott, szó szerint: nincs ISO-4217 ellenőrzés és nincs hosszkorlát, ezért ne feltételezd, hogy a mező három karakter."},"status":{"type":"string","description":"Az üzlet állapota. A Dynex felülete és ez az API ezt a négy értéket állítja be: `open` (nyitott), `won` (megnyert), `lost` (elveszített), `abandoned` (elejtett). Az adatbázisban viszont szabad szöveg, ezért egy régebbi vagy migrált sor ettől eltérőt is hordozhat: ne írj kimerítő elágazást a négy értékre, az ismeretlen státuszt is kezeld. Ilyen sor a lista `status` szűrőjével nem kérdezhető le, mert az csak a négy felsorolt értéket fogadja el."},"contactId":{"type":["string","null"],"description":"A kapcsolódó kontakt azonosítója, ha az üzlet CRM-kontakthoz van kötve. `null`, ha nincs kontakt kötve. A kontakt törlése után a mező megbízhatatlan: az API-n létrehozott üzletnél a kötés leválik és `null` lesz, miközben a `contactName`, `contactEmail` és `contactPhone` a korábban rámásolt értékkel megmarad - kitöltött kontaktnév melletti `null` azonosító tehát törölt kontaktot is jelenthet, nem csak azt, hogy sosem volt kötve. Régebbi üzleteknél a fordítottja is előfordulhat: az azonosító megmarad, de a `GET /contacts/{id}` már `404`-et ad rá. Ha élő kontaktra van szükséged, mindig ellenőrizd a `GET /contacts/{id}` végponttal."},"contactName":{"type":["string","null"],"description":"A kapcsolódó kontakt neve az üzlet létrehozásának pillanatában - pillanatfelvétel, nem élő hivatkozás. Ezen az API-n később NEM frissíthető: a `PATCH /deals/{id}` nem nyúl ehhez a mezőhöz, és `contactId`-t sem fogad. A kontakt átnevezése nem írja át visszamenőleg; a mindenkori aktuális névhez a `contactId` alapján a `GET /contacts/{id}` végpontot hívd."},"contactEmail":{"type":["string","null"],"description":"A kapcsolódó kontakt e-mail címe, az üzlet létrehozásakor rámásolva. Ezen az API-n később nem frissül - az aktuális értékhez a `GET /contacts/{id}` végpontot hívd."},"contactPhone":{"type":["string","null"],"description":"A kapcsolódó kontakt telefonszáma, az üzlet létrehozásakor rámásolva. Ezen az API-n később nem frissül - az aktuális értékhez a `GET /contacts/{id}` végpontot hívd."},"description":{"type":["string","null"],"description":"Szabad szöveges leírás az üzletről."},"tags":{"type":"array","items":{"type":"string"},"description":"Az üzlet címkéi. Mindig tömb, üresen `[]`."},"priority":{"type":["string","null"],"description":"Prioritás a fiók saját besorolása szerint (jellemzően `low`, `medium`, `high`). Ezen az API-n nem állítható és nem törölhető: sem a `POST /deals`, sem a `PATCH /deals/{id}` nem fogad `priority` mezőt, ezért az API-n létrehozott üzletnél mindig `null`. Értéket csak a Dynex felületén kaphat, ahol az új üzlet alapértéke `medium`."},"expectedCloseDate":{"type":["string","null"],"format":"date-time","description":"A várható lezárás tervezett időpontja UTC-ben. Ezen az API-n nem állítható és nem törölhető: sem a `POST /deals`, sem a `PATCH /deals/{id}` nem fogad `expectedCloseDate` mezőt, ezért az API-n létrehozott üzletnél mindig `null`. Értéket csak a Dynex felületén kaphat."},"closedAt":{"type":["string","null"],"format":"date-time","description":"A tényleges lezárás időpontja UTC-ben. Akkor telik meg, amikor az üzlet bármely nem `open` állapotba kerül: `won`, `lost` és `abandoned` esetén egyaránt, ezért a lezárás MÓDJÁRA ne ebből, hanem a `status` mezőből következtess. Ha az üzlet `open` állapotra vált vissza, a mező `null`-ra törlődik, és a korábbi lezárási időpont véglegesen elvész - a rendszer sehol nem őrzi meg."},"lostReason":{"type":["string","null"],"description":"Az elvesztés oka. Csak akkor íródik, amikor egy `PATCH /deals/{id}` a `status` mezőt `lost` értékre állítja. A későbbi állapotváltás nem törli, ezért egy újranyitott (`open`) vagy megnyert üzleten is ott maradhat a korábban rögzített ok - a jelenlegi állapotot a `status` mondja meg."},"createdAt":{"type":"string","format":"date-time","description":"Az üzlet létrejöttének időpontja UTC-ben."},"updatedAt":{"type":"string","format":"date-time","description":"Az utolsó módosítás időpontja UTC-ben."}},"required":["id","pipelineId","stageId","title","value","currency","status","contactId","contactName","contactEmail","contactPhone","description","tags","priority","expectedCloseDate","closedAt","lostReason","createdAt","updatedAt"]},"description":"A találatok az aktuális lapon, `createdAt` szerint csökkenő sorrendben."},"limit":{"type":"integer","description":"A ténylegesen alkalmazott lapméret."},"offset":{"type":"integer","description":"Az alkalmazott eltolás. A következő laphoz add hozzá a `limit` értékét."}},"required":["deals","limit","offset"]}}}},"400":{"description":"invalid_request: A séma-validáció bukott, vagy hiányzik egy kötelező paraméter. A `details[]` mezőnként sorolja fel az okot.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"401":{"description":"unauthorized: Hiányzó, hibás formátumú, ismeretlen, visszavont vagy lejárt token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"403":{"description":"forbidden: A token nem rendelkezik a szükséges scope-pal, a hívó IP nincs a kulcs allowlistáján, a fiók csomagja nem tartalmaz API-hozzáférést, vagy a fiók írás-tiltott (bemutató mód).","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"429":{"description":"rate_limited: A percalapú sebességkorlát (alapból 120 kérés/perc/kulcs) túllépve.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"500":{"description":"internal_error: Váratlan szerverhiba. Egyetlen végponton (`POST /contacts`) ugyanez a hiba a rövidebb `internal` kóddal érkezik - kezeld a kettőt azonosan.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}}}}},"/deals/{id}":{"delete":{"operationId":"deals.delete","tags":["deals"],"summary":"Üzlet törlése","description":"Véglegesen törli az üzletet. A művelet NEM visszavonható. A törlés továbbgyűrűzik: az üzlet teljes tevékenységnaplója (jegyzetek, szakaszváltások, státuszváltások) vele együtt megsemmisül, a hozzá kötött CRM-feladatok pedig megmaradnak, de a `dealId` mezőjük leválik. Ha csak lezárni akarod, a `PATCH /deals/{id}` végponton állítsd a `status` mezőt `won` vagy `lost` értékre - úgy az üzlet és a naplója is megmarad a riportokban.\n\nSzükséges scope: `deals.write`.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Erőforrás-azonosító"},"required":true,"description":"Erőforrás-azonosító","name":"id","in":"path"}],"responses":{"200":{"description":"Sikeres válasz","content":{"application/json":{"schema":{"type":"object","properties":{"deleted":{"type":"boolean","enum":[true],"description":"Mindig `true`, ha a törlés megtörtént."},"id":{"type":"string","description":"A törölt üzlet azonosítója."}},"required":["deleted","id"]}}}},"401":{"description":"unauthorized: Hiányzó, hibás formátumú, ismeretlen, visszavont vagy lejárt token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"403":{"description":"forbidden: A token nem rendelkezik a szükséges scope-pal, a hívó IP nincs a kulcs allowlistáján, a fiók csomagja nem tartalmaz API-hozzáférést, vagy a fiók írás-tiltott (bemutató mód).","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"404":{"description":"not_found: Az erőforrás nem létezik EBBEN a fiókban. Egy másik fiókhoz tartozó azonosító is ezt adja - a kettő szándékosan megkülönböztethetetlen.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"429":{"description":"rate_limited: A percalapú sebességkorlát (alapból 120 kérés/perc/kulcs) túllépve.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"500":{"description":"internal_error: Váratlan szerverhiba. Egyetlen végponton (`POST /contacts`) ugyanez a hiba a rövidebb `internal` kóddal érkezik - kezeld a kettőt azonosan.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}}}},"get":{"operationId":"deals.get","tags":["deals"],"summary":"Egy üzlet lekérdezése","description":"Egyetlen üzlet aktuális állapota azonosító alapján. Más fiók üzletére `404` a válasz.\n\nSzükséges scope: `deals.readonly`.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Erőforrás-azonosító"},"required":true,"description":"Erőforrás-azonosító","name":"id","in":"path"}],"responses":{"200":{"description":"Sikeres válasz","content":{"application/json":{"schema":{"type":"object","properties":{"deal":{"type":"object","properties":{"id":{"type":"string","description":"Az üzlet állandó azonosítója."},"pipelineId":{"type":"string","description":"Melyik pipeline-ban van az üzlet. A pipeline-okat a `GET /pipelines` listázza."},"stageId":{"type":"string","description":"Az aktuális szakasz azonosítója a pipeline-on belül. A szakaszok nevét és sorrendjét a `GET /pipelines` adja."},"title":{"type":"string","description":"Az üzlet megnevezése."},"value":{"type":"integer","description":"Az üzlet értéke egész forintban (nem fillérben). Ha nem adtak meg értéket, `0`."},"currency":{"type":"string","description":"Az érték pénzneme. Alapértelmezés `HUF`. Az API azt az értéket adja vissza, amit létrehozáskor kapott, szó szerint: nincs ISO-4217 ellenőrzés és nincs hosszkorlát, ezért ne feltételezd, hogy a mező három karakter."},"status":{"type":"string","description":"Az üzlet állapota. A Dynex felülete és ez az API ezt a négy értéket állítja be: `open` (nyitott), `won` (megnyert), `lost` (elveszített), `abandoned` (elejtett). Az adatbázisban viszont szabad szöveg, ezért egy régebbi vagy migrált sor ettől eltérőt is hordozhat: ne írj kimerítő elágazást a négy értékre, az ismeretlen státuszt is kezeld. Ilyen sor a lista `status` szűrőjével nem kérdezhető le, mert az csak a négy felsorolt értéket fogadja el."},"contactId":{"type":["string","null"],"description":"A kapcsolódó kontakt azonosítója, ha az üzlet CRM-kontakthoz van kötve. `null`, ha nincs kontakt kötve. A kontakt törlése után a mező megbízhatatlan: az API-n létrehozott üzletnél a kötés leválik és `null` lesz, miközben a `contactName`, `contactEmail` és `contactPhone` a korábban rámásolt értékkel megmarad - kitöltött kontaktnév melletti `null` azonosító tehát törölt kontaktot is jelenthet, nem csak azt, hogy sosem volt kötve. Régebbi üzleteknél a fordítottja is előfordulhat: az azonosító megmarad, de a `GET /contacts/{id}` már `404`-et ad rá. Ha élő kontaktra van szükséged, mindig ellenőrizd a `GET /contacts/{id}` végponttal."},"contactName":{"type":["string","null"],"description":"A kapcsolódó kontakt neve az üzlet létrehozásának pillanatában - pillanatfelvétel, nem élő hivatkozás. Ezen az API-n később NEM frissíthető: a `PATCH /deals/{id}` nem nyúl ehhez a mezőhöz, és `contactId`-t sem fogad. A kontakt átnevezése nem írja át visszamenőleg; a mindenkori aktuális névhez a `contactId` alapján a `GET /contacts/{id}` végpontot hívd."},"contactEmail":{"type":["string","null"],"description":"A kapcsolódó kontakt e-mail címe, az üzlet létrehozásakor rámásolva. Ezen az API-n később nem frissül - az aktuális értékhez a `GET /contacts/{id}` végpontot hívd."},"contactPhone":{"type":["string","null"],"description":"A kapcsolódó kontakt telefonszáma, az üzlet létrehozásakor rámásolva. Ezen az API-n később nem frissül - az aktuális értékhez a `GET /contacts/{id}` végpontot hívd."},"description":{"type":["string","null"],"description":"Szabad szöveges leírás az üzletről."},"tags":{"type":"array","items":{"type":"string"},"description":"Az üzlet címkéi. Mindig tömb, üresen `[]`."},"priority":{"type":["string","null"],"description":"Prioritás a fiók saját besorolása szerint (jellemzően `low`, `medium`, `high`). Ezen az API-n nem állítható és nem törölhető: sem a `POST /deals`, sem a `PATCH /deals/{id}` nem fogad `priority` mezőt, ezért az API-n létrehozott üzletnél mindig `null`. Értéket csak a Dynex felületén kaphat, ahol az új üzlet alapértéke `medium`."},"expectedCloseDate":{"type":["string","null"],"format":"date-time","description":"A várható lezárás tervezett időpontja UTC-ben. Ezen az API-n nem állítható és nem törölhető: sem a `POST /deals`, sem a `PATCH /deals/{id}` nem fogad `expectedCloseDate` mezőt, ezért az API-n létrehozott üzletnél mindig `null`. Értéket csak a Dynex felületén kaphat."},"closedAt":{"type":["string","null"],"format":"date-time","description":"A tényleges lezárás időpontja UTC-ben. Akkor telik meg, amikor az üzlet bármely nem `open` állapotba kerül: `won`, `lost` és `abandoned` esetén egyaránt, ezért a lezárás MÓDJÁRA ne ebből, hanem a `status` mezőből következtess. Ha az üzlet `open` állapotra vált vissza, a mező `null`-ra törlődik, és a korábbi lezárási időpont véglegesen elvész - a rendszer sehol nem őrzi meg."},"lostReason":{"type":["string","null"],"description":"Az elvesztés oka. Csak akkor íródik, amikor egy `PATCH /deals/{id}` a `status` mezőt `lost` értékre állítja. A későbbi állapotváltás nem törli, ezért egy újranyitott (`open`) vagy megnyert üzleten is ott maradhat a korábban rögzített ok - a jelenlegi állapotot a `status` mondja meg."},"createdAt":{"type":"string","format":"date-time","description":"Az üzlet létrejöttének időpontja UTC-ben."},"updatedAt":{"type":"string","format":"date-time","description":"Az utolsó módosítás időpontja UTC-ben."}},"required":["id","pipelineId","stageId","title","value","currency","status","contactId","contactName","contactEmail","contactPhone","description","tags","priority","expectedCloseDate","closedAt","lostReason","createdAt","updatedAt"]}},"required":["deal"]}}}},"401":{"description":"unauthorized: Hiányzó, hibás formátumú, ismeretlen, visszavont vagy lejárt token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"403":{"description":"forbidden: A token nem rendelkezik a szükséges scope-pal, a hívó IP nincs a kulcs allowlistáján, a fiók csomagja nem tartalmaz API-hozzáférést, vagy a fiók írás-tiltott (bemutató mód).","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"404":{"description":"not_found: Az erőforrás nem létezik EBBEN a fiókban. Egy másik fiókhoz tartozó azonosító is ezt adja - a kettő szándékosan megkülönböztethetetlen.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"429":{"description":"rate_limited: A percalapú sebességkorlát (alapból 120 kérés/perc/kulcs) túllépve.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"500":{"description":"internal_error: Váratlan szerverhiba. Egyetlen végponton (`POST /contacts`) ugyanez a hiba a rövidebb `internal` kóddal érkezik - kezeld a kettőt azonosan.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}}}},"patch":{"operationId":"deals.update","tags":["deals"],"summary":"Üzlet módosítása, szakaszváltás, lezárás","description":"Szakaszváltáskor elindul a szakaszváltás-automatizmus és sorba kerül a `deal.stage_changed` webhook. Egyik sem befolyásolja a választ: ha az automatizmus indítása hibázik, a hívás akkor is `200`-at ad a módosított üzlettel, és csak a szerverlogba kerül bejegyzés. A sikeres válasz tehát azt igazolja, hogy a mentés megtörtént, azt nem, hogy az automatizmus le is futott. A `lostReason` csak akkor mentődik, ha ugyanebben a kérésben a `status` értéke `lost`. Legalább egy ténylegesen VÁLTOZÁST hozó mezőt meg kell adni (`title`, `value`, `description`, `tags`, `stageId`, `status`), egyébként `400` a válasz: a `stageId` csak akkor számít módosításnak, ha eltér az üzlet jelenlegi szakaszától, a többi mező puszta jelenléte viszont akkor is módosításnak számít, ha az érték megegyezik a jelenlegivel. Az új `stageId` az üzlet SAJÁT pipeline-jának szakasza kell legyen; másik pipeline szakaszára `400`. Ha a törzs SÉMAILAG érvénytelen (rossz típus, ismeretlen enum-érték) ÉS az `{id}` sem létezik, a válasz `400`, nem `404` - a séma-ellenőrzés megelőzi a létezés-vizsgálatot, hogy egy formailag hibás kérés hívója se kapjon jelzést az erőforrás létezéséről. A sémailag ÉRVÉNYES, de üres `{}` törzs viszont átmegy a séma-ellenőrzésen, ezért ott a létezés-vizsgálat fut előbb: nem létező azonosítóra `404` a válasz, és csak létező erőforrásnál kapod meg a `400`-at.\n\nSzükséges scope: `deals.write`.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Erőforrás-azonosító"},"required":true,"description":"Erőforrás-azonosító","name":"id","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string","minLength":1,"description":"Az üzlet új megnevezése."},"stageId":{"type":"string","minLength":1,"maxLength":128,"description":"Az új szakasz azonosítója. Csak akkor számít módosításnak - és csak akkor indítja a szakaszváltás-automatizmust és a `deal.stage_changed` webhookot -, ha eltér az üzlet jelenlegi szakaszától; a jelenlegi szakasszal egyező érték önmagában küldve `400`-at ad. Az indítás nem garantált: ha hibázik, a válasz változatlanul `200`, ezért a lefutást az automatizmus saját futási előzményéből, a webhook megérkezését pedig a fogadó végpontodon ellenőrizd."},"status":{"type":"string","enum":["open","won","lost","abandoned"],"description":"Az üzlet új állapota. `won`, `lost` vagy `abandoned` értékre a `closedAt` a kérés idejére áll - akkor is, ha az üzlet már eddig is ebben az állapotban volt, tehát a korábbi lezárási időbélyeg felülíródik. `open` értékre a `closedAt` `null`-ra törlődik, és a korábbi lezárási időpont nem állítható vissza. Webhook csak `won` és `lost` esetén megy ki (`deal.won`, `deal.lost`), `abandoned` esetén nem."},"value":{"type":"number","minimum":0,"description":"Az üzlet új értéke egész forintban (nem fillérben). Nem lehet negatív. Törtszámot ne küldj: az API nem kerekít, az érték változtatás nélkül kerül az adatbázis egész típusú oszlopába, ezért a tizedes érték a mentést szerverhibára (`500`) futtathatja."},"description":{"description":"Az új leírás. `null` vagy üres string küldésével a mező törlődik; a kulcs elhagyása érintetlenül hagyja."},"tags":{"type":"array","items":{"type":"string"},"description":"A címkék TELJES új listája - felülírja a meglévőket."},"lostReason":{"description":"Az elvesztés oka. CSAK akkor íródik, ha ugyanebben a kérésben a `status` mező is `lost` értéket kap; önmagában küldve nem számít módosításnak, és ha nincs mellette más mező, a válasz `400`. FIGYELEM: `status: \"lost\"` mellett a mező MINDIG felülíródik, a kulcs elhagyása is - ha ilyenkor nem küldöd a `lostReason`-t (vagy `null`-t küldesz), a korábban rögzített ok törlődik. Ha meg akarod tartani, küldd újra az értékét is."}}}}}},"responses":{"200":{"description":"Sikeres válasz","content":{"application/json":{"schema":{"type":"object","properties":{"deal":{"type":"object","properties":{"id":{"type":"string","description":"Az üzlet állandó azonosítója."},"pipelineId":{"type":"string","description":"Melyik pipeline-ban van az üzlet. A pipeline-okat a `GET /pipelines` listázza."},"stageId":{"type":"string","description":"Az aktuális szakasz azonosítója a pipeline-on belül. A szakaszok nevét és sorrendjét a `GET /pipelines` adja."},"title":{"type":"string","description":"Az üzlet megnevezése."},"value":{"type":"integer","description":"Az üzlet értéke egész forintban (nem fillérben). Ha nem adtak meg értéket, `0`."},"currency":{"type":"string","description":"Az érték pénzneme. Alapértelmezés `HUF`. Az API azt az értéket adja vissza, amit létrehozáskor kapott, szó szerint: nincs ISO-4217 ellenőrzés és nincs hosszkorlát, ezért ne feltételezd, hogy a mező három karakter."},"status":{"type":"string","description":"Az üzlet állapota. A Dynex felülete és ez az API ezt a négy értéket állítja be: `open` (nyitott), `won` (megnyert), `lost` (elveszített), `abandoned` (elejtett). Az adatbázisban viszont szabad szöveg, ezért egy régebbi vagy migrált sor ettől eltérőt is hordozhat: ne írj kimerítő elágazást a négy értékre, az ismeretlen státuszt is kezeld. Ilyen sor a lista `status` szűrőjével nem kérdezhető le, mert az csak a négy felsorolt értéket fogadja el."},"contactId":{"type":["string","null"],"description":"A kapcsolódó kontakt azonosítója, ha az üzlet CRM-kontakthoz van kötve. `null`, ha nincs kontakt kötve. A kontakt törlése után a mező megbízhatatlan: az API-n létrehozott üzletnél a kötés leválik és `null` lesz, miközben a `contactName`, `contactEmail` és `contactPhone` a korábban rámásolt értékkel megmarad - kitöltött kontaktnév melletti `null` azonosító tehát törölt kontaktot is jelenthet, nem csak azt, hogy sosem volt kötve. Régebbi üzleteknél a fordítottja is előfordulhat: az azonosító megmarad, de a `GET /contacts/{id}` már `404`-et ad rá. Ha élő kontaktra van szükséged, mindig ellenőrizd a `GET /contacts/{id}` végponttal."},"contactName":{"type":["string","null"],"description":"A kapcsolódó kontakt neve az üzlet létrehozásának pillanatában - pillanatfelvétel, nem élő hivatkozás. Ezen az API-n később NEM frissíthető: a `PATCH /deals/{id}` nem nyúl ehhez a mezőhöz, és `contactId`-t sem fogad. A kontakt átnevezése nem írja át visszamenőleg; a mindenkori aktuális névhez a `contactId` alapján a `GET /contacts/{id}` végpontot hívd."},"contactEmail":{"type":["string","null"],"description":"A kapcsolódó kontakt e-mail címe, az üzlet létrehozásakor rámásolva. Ezen az API-n később nem frissül - az aktuális értékhez a `GET /contacts/{id}` végpontot hívd."},"contactPhone":{"type":["string","null"],"description":"A kapcsolódó kontakt telefonszáma, az üzlet létrehozásakor rámásolva. Ezen az API-n később nem frissül - az aktuális értékhez a `GET /contacts/{id}` végpontot hívd."},"description":{"type":["string","null"],"description":"Szabad szöveges leírás az üzletről."},"tags":{"type":"array","items":{"type":"string"},"description":"Az üzlet címkéi. Mindig tömb, üresen `[]`."},"priority":{"type":["string","null"],"description":"Prioritás a fiók saját besorolása szerint (jellemzően `low`, `medium`, `high`). Ezen az API-n nem állítható és nem törölhető: sem a `POST /deals`, sem a `PATCH /deals/{id}` nem fogad `priority` mezőt, ezért az API-n létrehozott üzletnél mindig `null`. Értéket csak a Dynex felületén kaphat, ahol az új üzlet alapértéke `medium`."},"expectedCloseDate":{"type":["string","null"],"format":"date-time","description":"A várható lezárás tervezett időpontja UTC-ben. Ezen az API-n nem állítható és nem törölhető: sem a `POST /deals`, sem a `PATCH /deals/{id}` nem fogad `expectedCloseDate` mezőt, ezért az API-n létrehozott üzletnél mindig `null`. Értéket csak a Dynex felületén kaphat."},"closedAt":{"type":["string","null"],"format":"date-time","description":"A tényleges lezárás időpontja UTC-ben. Akkor telik meg, amikor az üzlet bármely nem `open` állapotba kerül: `won`, `lost` és `abandoned` esetén egyaránt, ezért a lezárás MÓDJÁRA ne ebből, hanem a `status` mezőből következtess. Ha az üzlet `open` állapotra vált vissza, a mező `null`-ra törlődik, és a korábbi lezárási időpont véglegesen elvész - a rendszer sehol nem őrzi meg."},"lostReason":{"type":["string","null"],"description":"Az elvesztés oka. Csak akkor íródik, amikor egy `PATCH /deals/{id}` a `status` mezőt `lost` értékre állítja. A későbbi állapotváltás nem törli, ezért egy újranyitott (`open`) vagy megnyert üzleten is ott maradhat a korábban rögzített ok - a jelenlegi állapotot a `status` mondja meg."},"createdAt":{"type":"string","format":"date-time","description":"Az üzlet létrejöttének időpontja UTC-ben."},"updatedAt":{"type":"string","format":"date-time","description":"Az utolsó módosítás időpontja UTC-ben."}},"required":["id","pipelineId","stageId","title","value","currency","status","contactId","contactName","contactEmail","contactPhone","description","tags","priority","expectedCloseDate","closedAt","lostReason","createdAt","updatedAt"]}},"required":["deal"]}}}},"400":{"description":"invalid_request: A séma-validáció bukott, vagy hiányzik egy kötelező paraméter. A `details[]` mezőnként sorolja fel az okot.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"401":{"description":"unauthorized: Hiányzó, hibás formátumú, ismeretlen, visszavont vagy lejárt token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"403":{"description":"forbidden: A token nem rendelkezik a szükséges scope-pal, a hívó IP nincs a kulcs allowlistáján, a fiók csomagja nem tartalmaz API-hozzáférést, vagy a fiók írás-tiltott (bemutató mód).","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"404":{"description":"not_found: Az erőforrás nem létezik EBBEN a fiókban. Egy másik fiókhoz tartozó azonosító is ezt adja - a kettő szándékosan megkülönböztethetetlen.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"429":{"description":"rate_limited: A percalapú sebességkorlát (alapból 120 kérés/perc/kulcs) túllépve.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"500":{"description":"internal_error: Váratlan szerverhiba. Egyetlen végponton (`POST /contacts`) ugyanez a hiba a rövidebb `internal` kóddal érkezik - kezeld a kettőt azonosan.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}}}}},"/orders/{id}":{"get":{"operationId":"orders.get","tags":["orders"],"summary":"Egy rendelés lekérdezése","description":"Egyetlen, az étteremben felvett rendelés a tételsoraival és a teljes pénzügyi bontásával. Ismeretlen azonosítóra és más fiók rendelésére egyaránt `404` a válasz, a kettő szándékosan nem különböztethető meg. Számlát vagy nyugtát ez a végpont nem ad ki.\n\nSzükséges scope: `orders.readonly`.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Erőforrás-azonosító"},"required":true,"description":"Erőforrás-azonosító","name":"id","in":"path"}],"responses":{"200":{"description":"Sikeres válasz","content":{"application/json":{"schema":{"type":"object","properties":{"order":{"type":"object","properties":{"id":{"type":"string","description":"A rendelés állandó azonosítója."},"orderNumber":{"type":"string","description":"A rendelés emberi azonosítója, ez szerepel a konyhai jegyen. Nem azonos a nyugta számával: a nyugtának saját, `NY-` előtagú száma van, amit ez a végpont nem ad vissza. Átlátszatlan szöveg - ne parse-old, és ne következtess belőle dátumra vagy sorszámra. A rendelésfelvételből érkező sorok jellemzően `ÉÉÉÉHHNN-XXXX` alakúak (például `20260801-A1B2`), de más forrásból származó rendelések ettől eltérő alakot is hordozhatnak."},"type":{"type":"string","description":"A rendelés fajtája. Pontosan ezek egyike: `dine_in` (helyben fogyasztás), `takeaway` (elvitel), `delivery` (kiszállítás), `online`, `kiosk`, `qr_order`. Más érték nem fordulhat elő, az adatbázis zárt értékkészletet érvényesít."},"status":{"type":"string","description":"A rendelés állapota. Pontosan ezek egyike: `pending`, `confirmed`, `open`, `preparing`, `ready`, `served`, `completed`, `cancelled`, `void`. Más érték nem fordulhat elő, az adatbázis zárt értékkészletet érvényesít."},"tableName":{"type":["string","null"],"description":"Az asztal megnevezése, ha a rendelés felvételekor rögzült. Ha nem tartozik hozzá asztal, az érték `null` VAGY üres string (`\"\"`) - mindkét alak előfordul a meglévő sorokon, ezért üresség-vizsgálatnál mindkettőre készülj fel. A mező nincs a `type` mezőhöz kötve: elvitelre vagy kiszállításra felvett rendelés is hordozhat asztalnevet, ezért ne ebből következtess a rendelés fajtájára - arra a `type` való."},"contactId":{"type":["string","null"],"description":"A rendeléshez kötött kontakt azonosítója. `null`, ha a vendég nem azonosított."},"customerName":{"type":["string","null"],"description":"A vendég neve, ahogy a rendeléskor rögzült. Ha nem rögzült név, az érték `null` VAGY üres string (`\"\"`) - mindkét alak előfordul, ezért üresség-vizsgálatnál mindkettőre készülj fel."},"reservationId":{"type":["string","null"],"description":"Ahhoz a foglaláshoz tartozó azonosító, amelyből ez a rendelés keletkezett. `null`, ha nincs ilyen."},"items":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","description":"A tétel neve, ahogy a rendelés pillanatában szerepelt. Nem hivatkozás: az étlaptétel későbbi átnevezése ezt nem írja át."},"quantity":{"type":"integer","description":"A rendelt mennyiség."}},"required":["name","quantity"],"description":"Egy tételsor a rendelésből. A kasszarendszer további kulcsokat is elhelyezhet benne (jellemzően `unitPrice`, `totalPrice`, választott feltétek), ezért itt csak az a két mező szerepel, ami MINDIG jelen van."},"description":"A rendelés tételsorai a kasszarendszerből, változatlan alakban."},"subtotal":{"type":"integer","description":"A tételsorok összege egész forintban. BRUTTÓ érték: az áfát TARTALMAZZA, mert a tételárak bruttók. Ne add hozzá a `taxAmount`-ot - az ebben az összegben már benne van."},"taxAmount":{"type":"integer","description":"A `subtotal`-ban BENNE FOGLALT áfa összege egész forintban, tételenként a bruttó árból visszaszámolva. Tájékoztató bontás: nem adódik hozzá a fizetendő összeghez."},"discountAmount":{"type":"integer","description":"A levont kedvezmény egész forintban. Sosem negatív: a kedvezmény pozitív számként szerepel, kedvezmény nélkül az érték 0."},"tipAmount":{"type":"integer","description":"A rendelés sorára könyvelt borravaló egész forintban. FIGYELEM: ez a mező a gyakorlatban mindig 0, és a `totalAmount`-nak sem része. A borravaló a nyugtára került, nem a rendelésre, és a rendelés sorát utólag egyetlen írási út sem frissítette vele. Borravaló-bevételt ebből a mezőből ne összegezz: garantáltan 0-t kapsz."},"serviceFee":{"type":"integer","description":"A szervizdíj egész forintban. A `totalAmount`-hoz hozzáadódik."},"deliveryFee":{"type":"integer","description":"A kiszállítási díj egész forintban. A `totalAmount`-hoz hozzáadódik."},"totalAmount":{"type":"integer","description":"A ténylegesen fizetendő végösszeg egész forintban. Ez a mérvadó összeg - ne számold újra a többi mezőből. Tájékoztatásul a keletkezésekor alkalmazott képlet: `subtotal - discountAmount + serviceFee + deliveryFee` (nullára vágva). Az áfa a `subtotal`-ban már benne van, a `tipAmount` pedig nem része."},"notes":{"type":["string","null"],"description":"Megjegyzés a rendeléshez."},"source":{"type":"string","description":"A rendelés keletkezésének felülete. Tipikus értékek: `pos` (kassza), `kiosk` (kioszk), `storefront` (webshop), `mobile` (mobilalkalmazás), `qr` (QR-kódos asztali rendelés), `loyalty_app` (hűségalkalmazás), `phone` (telefonon felvett rendelés). Az adatbázisban ez szabad szöveges mező, nincs rá megkötés, ezért egy régebbi vagy külső rendszerből átvett sor ettől eltérőt is hordozhat - ismeretlen értékre is készülj fel. Nem azonos a `type` mezővel: az `online` például rendelésfajta és nem forrás."},"paymentMethod":{"type":["string","null"],"description":"A rendelés FELVÉTELEKOR rögzített fizetési mód (tipikusan `cash` vagy `card`). Nem fizetettség-jelző: a kasszán kiegyenlített rendelésen `null` marad, mert ott a fizetés módja a nyugtára kerül; a hűségalkalmazásból vagy telefonon érkező rendelés viszont már a létrehozás pillanatában kap értéket, jóval a fizetés előtt. `null`, ha a felvételkor nem adtak meg fizetési módot."},"scheduledPickupTime":{"type":["string","null"],"format":"date-time","description":"Az előre egyeztetett átvétel időpontja UTC-ben. `null`, ha nincs időzítve."},"deliveryAddress":{"type":["string","null"],"description":"A kiszállítási cím utca és házszám része. Csak kiszállításnál van kitöltve."},"deliveryCity":{"type":["string","null"],"description":"A kiszállítás települése."},"deliveryPostalCode":{"type":["string","null"],"description":"A kiszállítás irányítószáma."},"deliveryPhone":{"type":["string","null"],"description":"A futárnak megadott telefonszám. Eltérhet a kontakt telefonszámától."},"createdAt":{"type":"string","format":"date-time","description":"A rendelés felvételének időpontja UTC-ben."},"completedAt":{"type":["string","null"],"format":"date-time","description":"A rendelés lezárásának időpontja UTC-ben. `null`, amíg nincs lezárva."}},"required":["id","orderNumber","type","status","tableName","contactId","customerName","reservationId","items","subtotal","taxAmount","discountAmount","tipAmount","serviceFee","deliveryFee","totalAmount","notes","source","paymentMethod","scheduledPickupTime","deliveryAddress","deliveryCity","deliveryPostalCode","deliveryPhone","createdAt","completedAt"]}},"required":["order"]}}}},"401":{"description":"unauthorized: Hiányzó, hibás formátumú, ismeretlen, visszavont vagy lejárt token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"403":{"description":"forbidden: A token nem rendelkezik a szükséges scope-pal, a hívó IP nincs a kulcs allowlistáján, a fiók csomagja nem tartalmaz API-hozzáférést, vagy a fiók írás-tiltott (bemutató mód).","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"404":{"description":"not_found: Az erőforrás nem létezik EBBEN a fiókban. Egy másik fiókhoz tartozó azonosító is ezt adja - a kettő szándékosan megkülönböztethetetlen.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"429":{"description":"rate_limited: A percalapú sebességkorlát (alapból 120 kérés/perc/kulcs) túllépve.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"500":{"description":"internal_error: Váratlan szerverhiba. Egyetlen végponton (`POST /contacts`) ugyanez a hiba a rövidebb `internal` kóddal érkezik - kezeld a kettőt azonosan.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}}}}},"/orders":{"get":{"operationId":"orders.list","tags":["orders"],"summary":"Rendelések listázása","description":"A fiók éttermi rendelésfelvételéből (kassza, kioszk, QR-rendelés, hűségalkalmazás, telefon) származó rendelések lapozott listája, a legfrissebbel kezdve. A szűrők ÉS kapcsolattal érvényesülnek. Ez a végpont csak olvas: rendelést az API-n keresztül nem lehet létrehozni vagy módosítani.\n\nSzükséges scope: `orders.readonly`.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","enum":["pending","confirmed","open","preparing","ready","served","completed","cancelled","void"],"description":"Szűrés a rendelés állapotára."},"required":false,"description":"Szűrés a rendelés állapotára.","name":"status","in":"query"},{"schema":{"type":"string","enum":["dine_in","takeaway","delivery","online","kiosk","qr_order"],"description":"Szűrés a rendelés fajtájára."},"required":false,"description":"Szűrés a rendelés fajtájára.","name":"type","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":128,"description":"Csak az ehhez a kontakthoz kötött rendelések."},"required":false,"description":"Csak az ehhez a kontakthoz kötött rendelések.","name":"contactId","in":"query"},{"schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$","description":"Csak az ettől a naptól kezdve felvett rendelések. A határ UTC-éjfél (`ÉÉÉÉ-HH-NNT00:00:00Z`), nem a hely helyi éjfele: nyári időszámításban (UTC+2) a megadott nap helyi 02:00 órájától kapod a rendeléseket."},"required":false,"description":"Csak az ettől a naptól kezdve felvett rendelések. A határ UTC-éjfél (`ÉÉÉÉ-HH-NNT00:00:00Z`), nem a hely helyi éjfele: nyári időszámításban (UTC+2) a megadott nap helyi 02:00 órájától kapod a rendeléseket.","name":"dateFrom","in":"query"},{"schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$","description":"Csak az eddig a napig bezárólag felvett rendelések. A felső határ `ÉÉÉÉ-HH-NNT23:59:59.999Z`, szintén UTC szerint: nyáron (UTC+2) a következő helyi nap 02:00 órájáig felvett rendelések még beleesnek."},"required":false,"description":"Csak az eddig a napig bezárólag felvett rendelések. A felső határ `ÉÉÉÉ-HH-NNT23:59:59.999Z`, szintén UTC szerint: nyáron (UTC+2) a következő helyi nap 02:00 órájáig felvett rendelések még beleesnek.","name":"dateTo","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":200,"default":50,"description":"Találatok maximális száma (1-200, alapértelmezés 50; a tartományon kívüli érték a határra szorítódik, nem hibát ad)"},"required":false,"description":"Találatok maximális száma (1-200, alapértelmezés 50; a tartományon kívüli érték a határra szorítódik, nem hibát ad)","name":"limit","in":"query"},{"schema":{"type":"integer","minimum":0,"maximum":1000000,"default":0,"description":"Hány találatot ugorjon át (a tartományon kívüli érték a határra szorítódik, nem hibát ad)"},"required":false,"description":"Hány találatot ugorjon át (a tartományon kívüli érték a határra szorítódik, nem hibát ad)","name":"offset","in":"query"}],"responses":{"200":{"description":"Sikeres válasz","content":{"application/json":{"schema":{"type":"object","properties":{"orders":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"A rendelés állandó azonosítója."},"orderNumber":{"type":"string","description":"A rendelés emberi azonosítója, ez szerepel a konyhai jegyen. Nem azonos a nyugta számával: a nyugtának saját, `NY-` előtagú száma van, amit ez a végpont nem ad vissza. Átlátszatlan szöveg - ne parse-old, és ne következtess belőle dátumra vagy sorszámra. A rendelésfelvételből érkező sorok jellemzően `ÉÉÉÉHHNN-XXXX` alakúak (például `20260801-A1B2`), de más forrásból származó rendelések ettől eltérő alakot is hordozhatnak."},"type":{"type":"string","description":"A rendelés fajtája. Pontosan ezek egyike: `dine_in` (helyben fogyasztás), `takeaway` (elvitel), `delivery` (kiszállítás), `online`, `kiosk`, `qr_order`. Más érték nem fordulhat elő, az adatbázis zárt értékkészletet érvényesít."},"status":{"type":"string","description":"A rendelés állapota. Pontosan ezek egyike: `pending`, `confirmed`, `open`, `preparing`, `ready`, `served`, `completed`, `cancelled`, `void`. Más érték nem fordulhat elő, az adatbázis zárt értékkészletet érvényesít."},"tableName":{"type":["string","null"],"description":"Az asztal megnevezése, ha a rendelés felvételekor rögzült. Ha nem tartozik hozzá asztal, az érték `null` VAGY üres string (`\"\"`) - mindkét alak előfordul a meglévő sorokon, ezért üresség-vizsgálatnál mindkettőre készülj fel. A mező nincs a `type` mezőhöz kötve: elvitelre vagy kiszállításra felvett rendelés is hordozhat asztalnevet, ezért ne ebből következtess a rendelés fajtájára - arra a `type` való."},"contactId":{"type":["string","null"],"description":"A rendeléshez kötött kontakt azonosítója. `null`, ha a vendég nem azonosított."},"customerName":{"type":["string","null"],"description":"A vendég neve, ahogy a rendeléskor rögzült. Ha nem rögzült név, az érték `null` VAGY üres string (`\"\"`) - mindkét alak előfordul, ezért üresség-vizsgálatnál mindkettőre készülj fel."},"reservationId":{"type":["string","null"],"description":"Ahhoz a foglaláshoz tartozó azonosító, amelyből ez a rendelés keletkezett. `null`, ha nincs ilyen."},"items":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","description":"A tétel neve, ahogy a rendelés pillanatában szerepelt. Nem hivatkozás: az étlaptétel későbbi átnevezése ezt nem írja át."},"quantity":{"type":"integer","description":"A rendelt mennyiség."}},"required":["name","quantity"],"description":"Egy tételsor a rendelésből. A kasszarendszer további kulcsokat is elhelyezhet benne (jellemzően `unitPrice`, `totalPrice`, választott feltétek), ezért itt csak az a két mező szerepel, ami MINDIG jelen van."},"description":"A rendelés tételsorai a kasszarendszerből, változatlan alakban."},"subtotal":{"type":"integer","description":"A tételsorok összege egész forintban. BRUTTÓ érték: az áfát TARTALMAZZA, mert a tételárak bruttók. Ne add hozzá a `taxAmount`-ot - az ebben az összegben már benne van."},"taxAmount":{"type":"integer","description":"A `subtotal`-ban BENNE FOGLALT áfa összege egész forintban, tételenként a bruttó árból visszaszámolva. Tájékoztató bontás: nem adódik hozzá a fizetendő összeghez."},"discountAmount":{"type":"integer","description":"A levont kedvezmény egész forintban. Sosem negatív: a kedvezmény pozitív számként szerepel, kedvezmény nélkül az érték 0."},"tipAmount":{"type":"integer","description":"A rendelés sorára könyvelt borravaló egész forintban. FIGYELEM: ez a mező a gyakorlatban mindig 0, és a `totalAmount`-nak sem része. A borravaló a nyugtára került, nem a rendelésre, és a rendelés sorát utólag egyetlen írási út sem frissítette vele. Borravaló-bevételt ebből a mezőből ne összegezz: garantáltan 0-t kapsz."},"serviceFee":{"type":"integer","description":"A szervizdíj egész forintban. A `totalAmount`-hoz hozzáadódik."},"deliveryFee":{"type":"integer","description":"A kiszállítási díj egész forintban. A `totalAmount`-hoz hozzáadódik."},"totalAmount":{"type":"integer","description":"A ténylegesen fizetendő végösszeg egész forintban. Ez a mérvadó összeg - ne számold újra a többi mezőből. Tájékoztatásul a keletkezésekor alkalmazott képlet: `subtotal - discountAmount + serviceFee + deliveryFee` (nullára vágva). Az áfa a `subtotal`-ban már benne van, a `tipAmount` pedig nem része."},"notes":{"type":["string","null"],"description":"Megjegyzés a rendeléshez."},"source":{"type":"string","description":"A rendelés keletkezésének felülete. Tipikus értékek: `pos` (kassza), `kiosk` (kioszk), `storefront` (webshop), `mobile` (mobilalkalmazás), `qr` (QR-kódos asztali rendelés), `loyalty_app` (hűségalkalmazás), `phone` (telefonon felvett rendelés). Az adatbázisban ez szabad szöveges mező, nincs rá megkötés, ezért egy régebbi vagy külső rendszerből átvett sor ettől eltérőt is hordozhat - ismeretlen értékre is készülj fel. Nem azonos a `type` mezővel: az `online` például rendelésfajta és nem forrás."},"paymentMethod":{"type":["string","null"],"description":"A rendelés FELVÉTELEKOR rögzített fizetési mód (tipikusan `cash` vagy `card`). Nem fizetettség-jelző: a kasszán kiegyenlített rendelésen `null` marad, mert ott a fizetés módja a nyugtára kerül; a hűségalkalmazásból vagy telefonon érkező rendelés viszont már a létrehozás pillanatában kap értéket, jóval a fizetés előtt. `null`, ha a felvételkor nem adtak meg fizetési módot."},"scheduledPickupTime":{"type":["string","null"],"format":"date-time","description":"Az előre egyeztetett átvétel időpontja UTC-ben. `null`, ha nincs időzítve."},"deliveryAddress":{"type":["string","null"],"description":"A kiszállítási cím utca és házszám része. Csak kiszállításnál van kitöltve."},"deliveryCity":{"type":["string","null"],"description":"A kiszállítás települése."},"deliveryPostalCode":{"type":["string","null"],"description":"A kiszállítás irányítószáma."},"deliveryPhone":{"type":["string","null"],"description":"A futárnak megadott telefonszám. Eltérhet a kontakt telefonszámától."},"createdAt":{"type":"string","format":"date-time","description":"A rendelés felvételének időpontja UTC-ben."},"completedAt":{"type":["string","null"],"format":"date-time","description":"A rendelés lezárásának időpontja UTC-ben. `null`, amíg nincs lezárva."}},"required":["id","orderNumber","type","status","tableName","contactId","customerName","reservationId","items","subtotal","taxAmount","discountAmount","tipAmount","serviceFee","deliveryFee","totalAmount","notes","source","paymentMethod","scheduledPickupTime","deliveryAddress","deliveryCity","deliveryPostalCode","deliveryPhone","createdAt","completedAt"]},"description":"A találatok az aktuális lapon, felvétel szerint csökkenő sorrendben."},"limit":{"type":"integer","description":"A ténylegesen alkalmazott lapméret."},"offset":{"type":"integer","description":"Az alkalmazott eltolás. A következő laphoz add hozzá a `limit` értékét."}},"required":["orders","limit","offset"]}}}},"400":{"description":"invalid_request: A séma-validáció bukott, vagy hiányzik egy kötelező paraméter. A `details[]` mezőnként sorolja fel az okot.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"401":{"description":"unauthorized: Hiányzó, hibás formátumú, ismeretlen, visszavont vagy lejárt token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"403":{"description":"forbidden: A token nem rendelkezik a szükséges scope-pal, a hívó IP nincs a kulcs allowlistáján, a fiók csomagja nem tartalmaz API-hozzáférést, vagy a fiók írás-tiltott (bemutató mód).","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"429":{"description":"rate_limited: A percalapú sebességkorlát (alapból 120 kérés/perc/kulcs) túllépve.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"500":{"description":"internal_error: Váratlan szerverhiba. Egyetlen végponton (`POST /contacts`) ugyanez a hiba a rövidebb `internal` kóddal érkezik - kezeld a kettőt azonosan.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}}}}},"/menu":{"get":{"operationId":"menu.get","tags":["menu"],"summary":"Teljes étlap (kategóriák, tételek, feltét-csoportok)","description":"A teljes étlap egyetlen hívásban: a kategóriák a tételeikkel, mellettük külön tömbben a feltét-csoportok. A tételek a `modifierGroupIds` mezőn keresztül hivatkoznak a csoportokra, tehát a két tömböt neked kell összepárosítanod. A válasz csak a bekapcsolt kategóriákat és az étlapon lévő (aktív) tételeket tartalmazza, azon belül alapból csak az elérhetőeket - egy kikapcsolt kategória a tételeivel együtt hiányzik. A `modifierGroups` tömb szintén csak a ténylegesen visszaadott tételek által hivatkozott csoportokat tartalmazza, nem a fiók teljes csoportlistáját. Nem lapozható, és nagy étlapnál a válasz is nagy - érdemes gyorsítótárazni, nem minden oldalbetöltésnél lekérni.\n\nSzükséges scope: `menu.readonly`.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Az átmenetileg elfogyott (`isAvailable: false`) tételek is jöjjenek. Az étlapról levett, inaktív tételeket ez SEM hozza vissza: azok erről a végpontról semmilyen paraméterrel nem kérdezhetők le, egyesével a `GET /menu/items/{id}` adja csak vissza őket. Kizárólag a szó szerinti `true` érték kapcsolja be; minden más érték - `1`, `igen`, üres string is - kikapcsoltnak számít, és nem ad hibát."},"required":false,"description":"Az átmenetileg elfogyott (`isAvailable: false`) tételek is jöjjenek. Az étlapról levett, inaktív tételeket ez SEM hozza vissza: azok erről a végpontról semmilyen paraméterrel nem kérdezhetők le, egyesével a `GET /menu/items/{id}` adja csak vissza őket. Kizárólag a szó szerinti `true` érték kapcsolja be; minden más érték - `1`, `igen`, üres string is - kikapcsoltnak számít, és nem ad hibát.","name":"includeUnavailable","in":"query"}],"responses":{"200":{"description":"Sikeres válasz","content":{"application/json":{"schema":{"type":"object","properties":{"categories":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"A kategória azonosítója."},"name":{"type":"string","description":"A kategória magyar neve."},"nameEn":{"type":["string","null"],"description":"A kategória angol neve. `null`, ha nincs megadva."},"slug":{"type":"string","description":"A kategória URL-barát azonosítója."},"description":{"type":["string","null"],"description":"A kategória leírása."},"image":{"type":["string","null"],"description":"A kategória képének nyilvános hivatkozása."},"sortOrder":{"type":"integer","description":"A kategória helye az étlapon. A kisebb érték van elöl."},"parentCategoryId":{"type":["string","null"],"description":"A szülőkategória azonosítója alkategóriáknál. `null` a legfelső szinten."},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Az étlaptétel azonosítója. Ezt add át a `/menu/items/{id}` végpontoknak."},"name":{"type":"string","description":"A tétel magyar neve."},"nameEn":{"type":["string","null"],"description":"A tétel angol neve. `null`, ha nincs megadva."},"description":{"type":["string","null"],"description":"A tétel leírása a vendégnek."},"categoryId":{"type":"string","description":"Melyik étlapkategóriába tartozik a tétel."},"price":{"type":"integer","description":"A tétel ára egész forintban, áfával együtt."},"taxRate":{"type":"integer","description":"Az áfakulcs százalékban (például `27`), nem tizedes tört."},"image":{"type":["string","null"],"description":"A tétel képének nyilvános hivatkozása. `null`, ha nincs kép."},"isAvailable":{"type":"boolean","description":"`false`, ha a tétel átmenetileg elfogyott. A `GET /menu` alapból csak az elérhető tételeket adja, az elfogyottakat az `includeUnavailable=true` hozza. Ez a mező NEM azt mutatja, hogy a tétel étlapon van-e: egy inaktív, étlapról levett tételnél is lehet `true` - ilyen tételt csak a `GET /menu/items/{id}` ad vissza."},"allergens":{"type":"array","items":{"type":"string"},"description":"A tételben előforduló allergének kanonikus, ANGOL kódjai: `gluten`, `crustaceans`, `eggs`, `fish`, `peanuts`, `soy`, `milk`, `nuts`, `celery`, `mustard`, `sesame`, `sulphites`, `lupin`, `molluscs`. A magyar megnevezés (`Glutén`, `Zeller`) csak a felületen megjelenő címke, a mezőben SOSEM szerepel - a `glutén` stringre illesztés nem ad találatot. A lista nem zárt: régi vagy importált tételen a 14-es EU-listán kívüli kód (például `sulfit_e220`) is előfordulhat, ezért az ismeretlen kódot is jelenítsd meg, ne dobd el. Egy tételen legfeljebb 50 kód szerepelhet. Mindig tömb, üresen `[]`."},"variants":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"A változat azonosítója."},"name":{"type":"string","description":"A változat neve (például `0,3 l`, `nagy adag`)."},"price":{"type":"number","description":"A változathoz tárolt összeg forintban. Az API a tárolt értéket változatlanul adja vissza, és nem számol vele: nem adja hozzá a tétel `price` mezőjéhez, és nem is helyettesíti azzal. Hogy önálló árként vagy felárként kezeled, a te oldaladon dől el - a rendszer saját rendelési felületei (kassza, kioszk, online rendelés) ma nem használják a változatokat."}},"required":["id","name","price"]},"description":"A tétel méret- vagy kiszerelés-változatai. Mindig tömb, üresen `[]` - sosem `null`. Szabad szerkezetű mező: a tartalma ellenőrzés nélkül, úgy jön vissza, ahogy eltárolták, ezért régebben rögzített tételen egy-egy elemből hiányozhat az `id`, a `name` vagy a `price`, vagy más típusú lehet - olvasás előtt ellenőrizd."},"preparationTime":{"type":"integer","description":"A becsült elkészítési idő percben."},"sortOrder":{"type":"integer","description":"A tétel helye a kategórián belül. A kisebb érték van elöl."},"modifierGroupIds":{"type":"array","items":{"type":"string"},"description":"A tételhez tartozó feltét-csoportok azonosítói. A csoportok részleteit a válasz `modifierGroups` tömbje adja - ez a mező csak hivatkozás."},"channels":{"type":"object","properties":{"pos":{"type":"boolean","description":"Megjelenik-e a tétel a kasszán."},"kiosk":{"type":"boolean","description":"Megjelenik-e a tétel az önkiszolgáló kioszkon."},"online":{"type":"boolean","description":"Megjelenik-e a tétel az online rendelésben."},"loyaltyApp":{"type":"boolean","description":"Megjelenik-e a tétel a hűségprogram alkalmazásában."}},"required":["pos","kiosk","online","loyaltyApp"],"description":"Melyik értékesítési csatornán érhető el a tétel. Egy tétel több csatornán is szerepelhet."}},"required":["id","name","nameEn","description","categoryId","price","taxRate","image","isAvailable","allergens","variants","preparationTime","sortOrder","modifierGroupIds","channels"]},"description":"A kategóriába tartozó tételek, `sortOrder` szerint."}},"required":["id","name","nameEn","slug","description","image","sortOrder","parentCategoryId","items"]},"description":"Az étlap BEKAPCSOLT kategóriái `sortOrder` szerint, mindegyik a saját tételeivel. A kikapcsolt kategóriák nem jönnek vissza, és velük együtt a bennük lévő tételek is kimaradnak - akkor is, ha maguk a tételek elérhetők. Egy így kimaradt tétel a `GET /menu/items/{id}` végponton az azonosítójával továbbra is lekérdezhető."},"modifierGroups":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"A feltét-csoport azonosítója. Az étlaptételek `modifierGroupIds` mezője erre hivatkozik."},"name":{"type":"string","description":"A csoport neve, ahogy a vendégnek megjelenik (például `Köret`, `Extrák`)."},"isRequired":{"type":"boolean","description":"`true`, ha a vendégnek kötelező választania ebből a csoportból."},"minSelect":{"type":"integer","description":"Legalább ennyi feltétet kell választani a csoportból."},"maxSelect":{"type":"integer","description":"Legfeljebb ennyi feltét választható a csoportból."},"options":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"A feltét azonosítója."},"name":{"type":"string","description":"A feltét neve, ahogy a vendégnek megjelenik."},"price":{"type":"integer","description":"A feltét felára egész forintban. `0`, ha nem kerül külön pénzbe."},"isDefault":{"type":"boolean","description":"`true`, ha a feltét alapból ki van választva, amikor a vendég a tételt a kosárba teszi."}},"required":["id","name","price","isDefault"]},"description":"A csoportban választható feltétek."}},"required":["id","name","isRequired","minSelect","maxSelect","options"]},"description":"A válaszban visszaadott tételek által hivatkozott feltét-csoportok, egy szinten - NEM a fiók összes csoportja. A tételekhez a `modifierGroupIds` alapján rendeld hozzá őket. Ha egyetlen visszaadott tétel sem hivatkozik csoportra, a tömb üres. Mivel a halmaz a visszaadott tételekből épül, egy csak elfogyott tételen használt csoport alapból hiányzik - azt az `includeUnavailable=true` hozza elő. Teljes feltét-katalógushoz tehát `includeUnavailable=true` paraméterrel kérd le az étlapot."}},"required":["categories","modifierGroups"]}}}},"400":{"description":"invalid_request: A séma-validáció bukott, vagy hiányzik egy kötelező paraméter. A `details[]` mezőnként sorolja fel az okot.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"401":{"description":"unauthorized: Hiányzó, hibás formátumú, ismeretlen, visszavont vagy lejárt token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"403":{"description":"forbidden: A token nem rendelkezik a szükséges scope-pal, a hívó IP nincs a kulcs allowlistáján, a fiók csomagja nem tartalmaz API-hozzáférést, vagy a fiók írás-tiltott (bemutató mód).","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"429":{"description":"rate_limited: A percalapú sebességkorlát (alapból 120 kérés/perc/kulcs) túllépve.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"500":{"description":"internal_error: Váratlan szerverhiba. Egyetlen végponton (`POST /contacts`) ugyanez a hiba a rövidebb `internal` kóddal érkezik - kezeld a kettőt azonosan.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}}}}},"/menu/items/{id}":{"get":{"operationId":"menu.item_get","tags":["menu"],"summary":"Egy étlaptétel lekérdezése","description":"Egyetlen étlaptétel azonosító alapján. Nincs rajta elérhetőség- vagy étlapon-lét szerinti szűrés: az elfogyott és az étlapról levett, inaktív tételt is visszaadja, és akkor is, ha a tétel kategóriája ki van kapcsolva. A tétel feltét-csoportjait ez a végpont csak azonosítóként adja - a csoportok tartalmát a `GET /menu` válaszának `modifierGroups` tömbjéből vedd.\n\nSzükséges scope: `menu.readonly`.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Erőforrás-azonosító"},"required":true,"description":"Erőforrás-azonosító","name":"id","in":"path"}],"responses":{"200":{"description":"Sikeres válasz","content":{"application/json":{"schema":{"type":"object","properties":{"item":{"type":"object","properties":{"id":{"type":"string","description":"Az étlaptétel azonosítója. Ezt add át a `/menu/items/{id}` végpontoknak."},"name":{"type":"string","description":"A tétel magyar neve."},"nameEn":{"type":["string","null"],"description":"A tétel angol neve. `null`, ha nincs megadva."},"description":{"type":["string","null"],"description":"A tétel leírása a vendégnek."},"categoryId":{"type":"string","description":"Melyik étlapkategóriába tartozik a tétel."},"price":{"type":"integer","description":"A tétel ára egész forintban, áfával együtt."},"taxRate":{"type":"integer","description":"Az áfakulcs százalékban (például `27`), nem tizedes tört."},"image":{"type":["string","null"],"description":"A tétel képének nyilvános hivatkozása. `null`, ha nincs kép."},"isAvailable":{"type":"boolean","description":"`false`, ha a tétel átmenetileg elfogyott. A `GET /menu` alapból csak az elérhető tételeket adja, az elfogyottakat az `includeUnavailable=true` hozza. Ez a mező NEM azt mutatja, hogy a tétel étlapon van-e: egy inaktív, étlapról levett tételnél is lehet `true` - ilyen tételt csak a `GET /menu/items/{id}` ad vissza."},"allergens":{"type":"array","items":{"type":"string"},"description":"A tételben előforduló allergének kanonikus, ANGOL kódjai: `gluten`, `crustaceans`, `eggs`, `fish`, `peanuts`, `soy`, `milk`, `nuts`, `celery`, `mustard`, `sesame`, `sulphites`, `lupin`, `molluscs`. A magyar megnevezés (`Glutén`, `Zeller`) csak a felületen megjelenő címke, a mezőben SOSEM szerepel - a `glutén` stringre illesztés nem ad találatot. A lista nem zárt: régi vagy importált tételen a 14-es EU-listán kívüli kód (például `sulfit_e220`) is előfordulhat, ezért az ismeretlen kódot is jelenítsd meg, ne dobd el. Egy tételen legfeljebb 50 kód szerepelhet. Mindig tömb, üresen `[]`."},"variants":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"A változat azonosítója."},"name":{"type":"string","description":"A változat neve (például `0,3 l`, `nagy adag`)."},"price":{"type":"number","description":"A változathoz tárolt összeg forintban. Az API a tárolt értéket változatlanul adja vissza, és nem számol vele: nem adja hozzá a tétel `price` mezőjéhez, és nem is helyettesíti azzal. Hogy önálló árként vagy felárként kezeled, a te oldaladon dől el - a rendszer saját rendelési felületei (kassza, kioszk, online rendelés) ma nem használják a változatokat."}},"required":["id","name","price"]},"description":"A tétel méret- vagy kiszerelés-változatai. Mindig tömb, üresen `[]` - sosem `null`. Szabad szerkezetű mező: a tartalma ellenőrzés nélkül, úgy jön vissza, ahogy eltárolták, ezért régebben rögzített tételen egy-egy elemből hiányozhat az `id`, a `name` vagy a `price`, vagy más típusú lehet - olvasás előtt ellenőrizd."},"preparationTime":{"type":"integer","description":"A becsült elkészítési idő percben."},"sortOrder":{"type":"integer","description":"A tétel helye a kategórián belül. A kisebb érték van elöl."},"modifierGroupIds":{"type":"array","items":{"type":"string"},"description":"A tételhez tartozó feltét-csoportok azonosítói. A csoportok részleteit a válasz `modifierGroups` tömbje adja - ez a mező csak hivatkozás."},"channels":{"type":"object","properties":{"pos":{"type":"boolean","description":"Megjelenik-e a tétel a kasszán."},"kiosk":{"type":"boolean","description":"Megjelenik-e a tétel az önkiszolgáló kioszkon."},"online":{"type":"boolean","description":"Megjelenik-e a tétel az online rendelésben."},"loyaltyApp":{"type":"boolean","description":"Megjelenik-e a tétel a hűségprogram alkalmazásában."}},"required":["pos","kiosk","online","loyaltyApp"]}},"required":["id","name","nameEn","description","categoryId","price","taxRate","image","isAvailable","allergens","variants","preparationTime","sortOrder","modifierGroupIds","channels"]}},"required":["item"]}}}},"401":{"description":"unauthorized: Hiányzó, hibás formátumú, ismeretlen, visszavont vagy lejárt token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"403":{"description":"forbidden: A token nem rendelkezik a szükséges scope-pal, a hívó IP nincs a kulcs allowlistáján, a fiók csomagja nem tartalmaz API-hozzáférést, vagy a fiók írás-tiltott (bemutató mód).","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"404":{"description":"not_found: Az erőforrás nem létezik EBBEN a fiókban. Egy másik fiókhoz tartozó azonosító is ezt adja - a kettő szándékosan megkülönböztethetetlen.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"429":{"description":"rate_limited: A percalapú sebességkorlát (alapból 120 kérés/perc/kulcs) túllépve.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"500":{"description":"internal_error: Váratlan szerverhiba. Egyetlen végponton (`POST /contacts`) ugyanez a hiba a rövidebb `internal` kóddal érkezik - kezeld a kettőt azonosan.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}}}},"patch":{"operationId":"menu.item_update","tags":["menu"],"summary":"Ár és elérhetőség módosítása (POS-szinkron)","description":"A kassza és az étlap összehangolására való: egy tételnek CSAK az árát és az elérhetőségét lehet átírni. A név, a leírás, a kategória, az áfakulcs és a feltétek az API-ból nem módosíthatók - azokat a felületen kell szerkeszteni. Ha mégis beleírod őket a törzsbe, a kérés NEM hibázik: a nem támogatott mezők csendben kimaradnak a feldolgozásból, a támogatottak pedig érvényesülnek. A `{\"price\": 2400, \"name\": \"Új név\"}` törzsre tehát `200` a válasz, az ár átíródik, a név viszont változatlan marad - a válaszban visszaadott tétel a régi nevet mutatja. Ezt mindig a válasz tételén ellenőrizd, ne a beküldött törzsön. Legalább az egyiket (`price` vagy `isAvailable`) meg kell adni: üres törzsre `400` a válasz, és kizárólag ez az az eset, amikor a nem támogatott mezők küldése hibát ad, mert ilyenkor egyetlen támogatott mező sincs a törzsben. Ez az ellenőrzés viszont a tétel létezésének vizsgálata UTÁN fut, tehát üres törzs és ismeretlen `{id}` együtt `404`-et ad, nem `400`-at. Ha a törzs SÉMAILAG érvénytelen (rossz típus, ismeretlen enum-érték) ÉS az `{id}` sem létezik, a válasz `400`, nem `404` - a séma-ellenőrzés megelőzi a létezés-vizsgálatot, hogy egy formailag hibás kérés hívója se kapjon jelzést az erőforrás létezéséről. A sémailag ÉRVÉNYES, de üres `{}` törzs viszont átmegy a séma-ellenőrzésen, ezért ott a létezés-vizsgálat fut előbb: nem létező azonosítóra `404` a válasz, és csak létező erőforrásnál kapod meg a `400`-at.\n\nSzükséges scope: `menu.write`.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Erőforrás-azonosító"},"required":true,"description":"Erőforrás-azonosító","name":"id","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"price":{"type":"integer","minimum":0,"maximum":10000000,"description":"Az új ár egész forintban, áfával együtt. Nem lehet negatív, és nem lehet 10 000 000 fölött."},"isAvailable":{"type":"boolean","description":"`false` értékkel a tétel elfogyottra állítható, `true` értékkel visszakapcsolható."}}}}}},"responses":{"200":{"description":"Sikeres válasz","content":{"application/json":{"schema":{"type":"object","properties":{"item":{"type":"object","properties":{"id":{"type":"string","description":"Az étlaptétel azonosítója. Ezt add át a `/menu/items/{id}` végpontoknak."},"name":{"type":"string","description":"A tétel magyar neve."},"nameEn":{"type":["string","null"],"description":"A tétel angol neve. `null`, ha nincs megadva."},"description":{"type":["string","null"],"description":"A tétel leírása a vendégnek."},"categoryId":{"type":"string","description":"Melyik étlapkategóriába tartozik a tétel."},"price":{"type":"integer","description":"A tétel ára egész forintban, áfával együtt."},"taxRate":{"type":"integer","description":"Az áfakulcs százalékban (például `27`), nem tizedes tört."},"image":{"type":["string","null"],"description":"A tétel képének nyilvános hivatkozása. `null`, ha nincs kép."},"isAvailable":{"type":"boolean","description":"`false`, ha a tétel átmenetileg elfogyott. A `GET /menu` alapból csak az elérhető tételeket adja, az elfogyottakat az `includeUnavailable=true` hozza. Ez a mező NEM azt mutatja, hogy a tétel étlapon van-e: egy inaktív, étlapról levett tételnél is lehet `true` - ilyen tételt csak a `GET /menu/items/{id}` ad vissza."},"allergens":{"type":"array","items":{"type":"string"},"description":"A tételben előforduló allergének kanonikus, ANGOL kódjai: `gluten`, `crustaceans`, `eggs`, `fish`, `peanuts`, `soy`, `milk`, `nuts`, `celery`, `mustard`, `sesame`, `sulphites`, `lupin`, `molluscs`. A magyar megnevezés (`Glutén`, `Zeller`) csak a felületen megjelenő címke, a mezőben SOSEM szerepel - a `glutén` stringre illesztés nem ad találatot. A lista nem zárt: régi vagy importált tételen a 14-es EU-listán kívüli kód (például `sulfit_e220`) is előfordulhat, ezért az ismeretlen kódot is jelenítsd meg, ne dobd el. Egy tételen legfeljebb 50 kód szerepelhet. Mindig tömb, üresen `[]`."},"variants":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"A változat azonosítója."},"name":{"type":"string","description":"A változat neve (például `0,3 l`, `nagy adag`)."},"price":{"type":"number","description":"A változathoz tárolt összeg forintban. Az API a tárolt értéket változatlanul adja vissza, és nem számol vele: nem adja hozzá a tétel `price` mezőjéhez, és nem is helyettesíti azzal. Hogy önálló árként vagy felárként kezeled, a te oldaladon dől el - a rendszer saját rendelési felületei (kassza, kioszk, online rendelés) ma nem használják a változatokat."}},"required":["id","name","price"]},"description":"A tétel méret- vagy kiszerelés-változatai. Mindig tömb, üresen `[]` - sosem `null`. Szabad szerkezetű mező: a tartalma ellenőrzés nélkül, úgy jön vissza, ahogy eltárolták, ezért régebben rögzített tételen egy-egy elemből hiányozhat az `id`, a `name` vagy a `price`, vagy más típusú lehet - olvasás előtt ellenőrizd."},"preparationTime":{"type":"integer","description":"A becsült elkészítési idő percben."},"sortOrder":{"type":"integer","description":"A tétel helye a kategórián belül. A kisebb érték van elöl."},"modifierGroupIds":{"type":"array","items":{"type":"string"},"description":"A tételhez tartozó feltét-csoportok azonosítói. A csoportok részleteit a válasz `modifierGroups` tömbje adja - ez a mező csak hivatkozás."},"channels":{"type":"object","properties":{"pos":{"type":"boolean","description":"Megjelenik-e a tétel a kasszán."},"kiosk":{"type":"boolean","description":"Megjelenik-e a tétel az önkiszolgáló kioszkon."},"online":{"type":"boolean","description":"Megjelenik-e a tétel az online rendelésben."},"loyaltyApp":{"type":"boolean","description":"Megjelenik-e a tétel a hűségprogram alkalmazásában."}},"required":["pos","kiosk","online","loyaltyApp"]}},"required":["id","name","nameEn","description","categoryId","price","taxRate","image","isAvailable","allergens","variants","preparationTime","sortOrder","modifierGroupIds","channels"]}},"required":["item"]}}}},"400":{"description":"invalid_request: A séma-validáció bukott, vagy hiányzik egy kötelező paraméter. A `details[]` mezőnként sorolja fel az okot.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"401":{"description":"unauthorized: Hiányzó, hibás formátumú, ismeretlen, visszavont vagy lejárt token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"403":{"description":"forbidden: A token nem rendelkezik a szükséges scope-pal, a hívó IP nincs a kulcs allowlistáján, a fiók csomagja nem tartalmaz API-hozzáférést, vagy a fiók írás-tiltott (bemutató mód).","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"404":{"description":"not_found: Az erőforrás nem létezik EBBEN a fiókban. Egy másik fiókhoz tartozó azonosító is ezt adja - a kettő szándékosan megkülönböztethetetlen.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"429":{"description":"rate_limited: A percalapú sebességkorlát (alapból 120 kérés/perc/kulcs) túllépve.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"500":{"description":"internal_error: Váratlan szerverhiba. Egyetlen végponton (`POST /contacts`) ugyanez a hiba a rövidebb `internal` kóddal érkezik - kezeld a kettőt azonosan.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}}}}},"/loyalty/balance":{"get":{"operationId":"loyalty.balance","tags":["loyalty"],"summary":"Hűségtag egyenlege","description":"Egy hűségtag pontjai, szintje és wallet-kártyája egyetlen hívásban. A kontaktot `contactId`, `email` vagy `phone` alapján azonosítod - legalább az egyiket meg kell adni, egyébként `400` a válasz. Ha többet küldesz, a sorrend dönt: a `contactId` erősebb az `email`-nél, az `email` pedig a `phone`-nál, a gyengébb szűrőt a végpont figyelmen kívül hagyja. `404` kizárólag akkor jön, ha ilyen kontakt egyáltalán nincs a fiókban: a végpont a hűségtagságot nem vizsgálja, ezért egy hűségprogramban nem szereplő kontakt is `200`-at kap `loyaltyPoints: 0`, `loyaltyTier: null` és `pass: null` értékekkel - a `200` tehát önmagában nem bizonyítja a tagságot. Az `email` és a `phone` több kontaktra is illeszkedhet, lásd a figyelmeztetéseket. Ez a végpont csak olvas: pontot jóváírni vagy levonni ezen a v3 API-n nem lehet - pontot a kasszaoldali Partner API (hűségkártya / POS) mozgat.\n\nSzükséges scope: `loyalty.readonly`.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","minLength":1,"maxLength":128,"description":"A tag kontakt-azonosítója. Ez a legpontosabb azonosítás; ha megadod, a többi szűrő nem számít."},"required":false,"description":"A tag kontakt-azonosítója. Ez a legpontosabb azonosítás; ha megadod, a többi szűrő nem számít.","name":"contactId","in":"query"},{"schema":{"type":"string","description":"A tag e-mail címe. Pontos egyezés, a kis- és nagybetű nem számít. Csak akkor érvényesül, ha `contactId`-t nem adtál meg."},"required":false,"description":"A tag e-mail címe. Pontos egyezés, a kis- és nagybetű nem számít. Csak akkor érvényesül, ha `contactId`-t nem adtál meg.","name":"email","in":"query"},{"schema":{"type":"string","description":"A tag telefonszáma. A szóközök nem számítanak: a `+36 30 123 4567` és a `+36301234567` ugyanazt a tagot találja meg. Minden más karakternek egyeznie kell a rögzített alakkal, ezért kötőjel, zárójel, illetve `06` és `+36` eltérés esetén nincs találat. Csak akkor érvényesül, ha sem `contactId`-t, sem `email`-t nem adtál meg."},"required":false,"description":"A tag telefonszáma. A szóközök nem számítanak: a `+36 30 123 4567` és a `+36301234567` ugyanazt a tagot találja meg. Minden más karakternek egyeznie kell a rögzített alakkal, ezért kötőjel, zárójel, illetve `06` és `+36` eltérés esetén nincs találat. Csak akkor érvényesül, ha sem `contactId`-t, sem `email`-t nem adtál meg.","name":"phone","in":"query"}],"responses":{"200":{"description":"Sikeres válasz","content":{"application/json":{"schema":{"type":"object","properties":{"contactId":{"type":"string","description":"A megtalált tag kontakt-azonosítója. Akkor is visszajön, ha e-mail vagy telefon alapján kerestél - érdemes eltenni a további hívásokhoz."},"name":{"type":["string","null"],"description":"A tag teljes neve, vezeték- és keresztnév összefűzve. `null`, ha egyik névmező sincs kitöltve."},"email":{"type":["string","null"],"description":"A tag e-mail címe. `null`, ha nincs rögzítve."},"phone":{"type":["string","null"],"description":"A tag telefonszáma. `null`, ha nincs rögzítve."},"loyaltyPoints":{"type":"integer","description":"A tag aktuális pontegyenlege a kontakton nyilvántartva - vitás esetben ez a mérvadó, nem a kártyához tárolt `pass.points`. Figyelem: ha a kontakton egyáltalán nincs pont-nyilvántartás (jellemzően olyan kontakt, aki soha nem lett hűségtag), szintén `0` jön vissza. A `0` tehát két esetet mos össze: van nyilvántartás nulla ponttal, illetve nincs nyilvántartás. Ha ez a különbség számít, ne csak ebből a mezőből dönts."},"loyaltyTier":{"type":["string","null"],"description":"A tag hűségszintje a fiók saját elnevezésével (például `ezüst`). `null`, ha ehhez a taghoz nincs szint rendelve - például mert a kontakt nem hűségtag, vagy még nem volt pontmozgása. A szint a pontmozgásoknál áll be, ezért egyetlen `null` válaszból ne következtess arra, hogy a fiók nem használ szinteket."},"totals":{"type":"object","properties":{"reservations":{"type":"integer","description":"Hány foglalása volt eddig a tagnak."},"orders":{"type":"integer","description":"Hány rendelése volt eddig a tagnak."},"spent":{"type":"integer","description":"A tag összes eddigi költése egész pénzegységben, tizedesek nélkül. A rögzített tételek pénznemtől függetlenül, átváltás nélkül adódnak össze ebbe az egy számba, ezért pontosan forintot csak akkor jelent, ha a fiók kizárólag HUF-os tételeket rögzít (ez az alapértelmezés)."}},"required":["reservations","orders","spent"]},"pass":{"type":["object","null"],"properties":{"cardToken":{"type":"string","description":"A wallet-kártya belső azonosító tokenje. Nem ez van a kártya QR-kódjában: a QR a kártyaszámot tartalmazza, és csak akkor esik vissza erre a tokenre, ha a kártyához nincs kártyaszám rögzítve. A kártyaszámot ez a végpont nem adja ki, ezért egy beolvasott kódot ne ehhez a mezőhöz hasonlíts."},"status":{"type":"string","description":"A kártya állapota. Négy lehetséges érték: `active` (élő kártya), `suspended` (felfüggesztve, mert a tagot befagyasztották vagy törölték), `expired` (lejárt) és `revoked` (visszavont). A gyakorlatban ma csak az `active` és a `suspended` fordul elő, és a `suspended` a feloldás után újra `active` lesz. Beváltásra csak `active` kártyát fogadj el."},"points":{"type":"integer","description":"A kártyához tárolt pont-pillanatkép. Nem ez az érték jelenik meg a kártyán: a kártya mindig a `loyaltyPoints` egyenleget mutatja. A pillanatképet a kasszai tranzakciók léptetik, de nem minden pontmozgás írja: az adminisztrátori pontkorrekció például csak a `loyaltyPoints` egyenleget lépteti, ezért a két érték tartósan eltérhet. Elszámoláshoz és megjelenítéshez a `loyaltyPoints` a mérvadó."},"giftBalance":{"type":"integer","description":"Ajándékkártya-egyenleg egész forintban."},"stamps":{"type":"integer","description":"Az összegyűjtött pecsétek száma, ha a fiók pecsétgyűjtő kártyát használ."}},"required":["cardToken","status","points","giftBalance","stamps"],"description":"A kontakt digitális kártyájának pillanatképe. `null`, ha nincs kiadott kártyája - például mert nem hűségtag, vagy még nem váltotta ki. Az Apple/Google Wallet hivatkozásokat és a kártyaszámot ez a végpont nem adja ki."}},"required":["contactId","name","email","phone","loyaltyPoints","loyaltyTier","totals","pass"]}}}},"400":{"description":"invalid_request: A séma-validáció bukott, vagy hiányzik egy kötelező paraméter. A `details[]` mezőnként sorolja fel az okot.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"401":{"description":"unauthorized: Hiányzó, hibás formátumú, ismeretlen, visszavont vagy lejárt token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"403":{"description":"forbidden: A token nem rendelkezik a szükséges scope-pal, a hívó IP nincs a kulcs allowlistáján, a fiók csomagja nem tartalmaz API-hozzáférést, vagy a fiók írás-tiltott (bemutató mód).","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"404":{"description":"not_found: Az erőforrás nem létezik EBBEN a fiókban. Egy másik fiókhoz tartozó azonosító is ezt adja - a kettő szándékosan megkülönböztethetetlen.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"429":{"description":"rate_limited: A percalapú sebességkorlát (alapból 120 kérés/perc/kulcs) túllépve.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"500":{"description":"internal_error: Váratlan szerverhiba. Egyetlen végponton (`POST /contacts`) ugyanez a hiba a rövidebb `internal` kóddal érkezik - kezeld a kettőt azonosan.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}}}}},"/reviews":{"get":{"operationId":"reviews.list","tags":["reviews"],"summary":"Értékelések listázása","description":"A fiókhoz beérkezett értékelések lapozott listája, a legfrissebbel kezdve, platformtól függetlenül egyetlen egységes alakban. Ez a végpont csak olvas: értékelést az API-n keresztül nem lehet létrehozni, sem válaszolni rá.\n\nSzükséges scope: `reviews.readonly`.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","enum":["google","facebook","tripadvisor","internal"],"description":"Csak erről a platformról érkezett értékelések. A lista a korábbi rendszerből átvett (`dynexv2` platformú) értékeléseket is tartalmazza, azokat ez a szűrő nem tudja sem kiválasztani, sem kizárni."},"required":false,"description":"Csak erről a platformról érkezett értékelések. A lista a korábbi rendszerből átvett (`dynexv2` platformú) értékeléseket is tartalmazza, azokat ez a szűrő nem tudja sem kiválasztani, sem kizárni.","name":"platform","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":5,"description":"Legalább ennyi csillagos értékelések. Az `1` érték nem szűr semmit (minden értékelés legalább egy csillagos), tehát a szűrés `2`-től kezd hatni. Az 1-5 tartományon kívüli érték nem hibázik, a rendszer a legközelebbi határra szorítja. A `facebook` platform soraira - a bináris ajánlás 1-re és 5-re képzése miatt - a 2 és 5 közötti küszöbök mind ugyanazt a halmazt adják vissza, csak az ajánló értékeléseket."},"required":false,"description":"Legalább ennyi csillagos értékelések. Az `1` érték nem szűr semmit (minden értékelés legalább egy csillagos), tehát a szűrés `2`-től kezd hatni. Az 1-5 tartományon kívüli érték nem hibázik, a rendszer a legközelebbi határra szorítja. A `facebook` platform soraira - a bináris ajánlás 1-re és 5-re képzése miatt - a 2 és 5 közötti küszöbök mind ugyanazt a halmazt adják vissza, csak az ajánló értékeléseket.","name":"minRating","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":200,"default":50,"description":"Találatok maximális száma (1-200, alapértelmezés 50; a tartományon kívüli érték a határra szorítódik, nem hibát ad)"},"required":false,"description":"Találatok maximális száma (1-200, alapértelmezés 50; a tartományon kívüli érték a határra szorítódik, nem hibát ad)","name":"limit","in":"query"},{"schema":{"type":"integer","minimum":0,"maximum":1000000,"default":0,"description":"Hány találatot ugorjon át (a tartományon kívüli érték a határra szorítódik, nem hibát ad)"},"required":false,"description":"Hány találatot ugorjon át (a tartományon kívüli érték a határra szorítódik, nem hibát ad)","name":"offset","in":"query"}],"responses":{"200":{"description":"Sikeres válasz","content":{"application/json":{"schema":{"type":"object","properties":{"reviews":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Az értékelés azonosítója a Dynexben. Nem azonos a platform saját azonosítójával."},"platform":{"type":"string","description":"Honnan érkezett az értékelés: `google` (a Google Cégprofil-szinkronból), `facebook` (a Facebook-szinkronból), `dynexv2` (a korábbi rendszerből átvett, importált értékelés), illetve `tripadvisor` és `internal`. FIGYELEM: az utóbbi kettő kizárólag TÖRTÉNETI érték - ma egyetlen út sem hoz létre ilyen sort, mert kézi értékelés-rögzítés sem az API-n, sem a kezelőfelületen nincs. A lista idővel bővülhet, ezért ismeretlen értékre is készülj fel - ne építs a mezőre kimerítő elágazást."},"rating":{"type":"integer","description":"A csillagos értékelés, 1 és 5 között. Figyelem: a `facebook` platformról érkező soroknál ez nem valódi csillagszám - a Facebook ajánlás bináris (ajánlja / nem ajánlja), amit a rendszer 5-re, illetve 1-re képez le. A facebookos értékelések ezért kizárólag 1-es vagy 5-ös értéket vesznek fel; platformok közötti átlagolásnál vagy csillag-eloszlás számításánál ezt vedd figyelembe."},"content":{"type":"string","description":"Az értékelés szövege. Üres string, ha a vendég csak csillagot adott, szöveget nem írt - sosem `null`."},"customerName":{"type":"string","description":"Az értékelő neve. Ha a platform nem ad nevet (névtelen Google-értékelés, illetve név nélkül érkező Facebook-esemény), a rendszer helyettesítő szöveget ír be: Google-nél `Vendég` vagy `Névtelen vendég`, Facebooknál `Facebook felhasználó`. Ezek nem valódi nevek, ezért megszólítás generálásához vagy névpárosításhoz önmagában ne használd - hogy az értékelőt sikerült-e beazonosítani, azt a `contactId` mutatja meg. Sosem `null`."},"contactId":{"type":["string","null"],"description":"A hozzárendelt CRM-kontakt azonosítója, ha az értékelőt sikerült beazonosítani. `null`, ha nem."},"response":{"type":["string","null"],"description":"A hely nyilvános válasza az értékelésre. Válasz hiányában a mező forrástól függően üres string (\"\") vagy `null` - a Google- és Facebook-értékeléseknél üres string. Azt, hogy született-e már válasz, a `respondedAt` alapján döntsd el: az válasz nélkül mindig `null`."},"respondedAt":{"type":["string","null"],"format":"date-time","description":"A válasz kiküldésének időpontja UTC-ben. `null`, amíg nincs válasz."},"status":{"type":"string","description":"Az értékelés feldolgozottsága a fiók munkafolyamatában. Lehetséges értékek: `pending` (még nincs válasz), `responded` (van kiküldött válasz - egy értékelés már beérkezéskor is ilyen lehet, ha a véleményt a platformon korábban megválaszolták), `flagged` (a fiók kivizsgálásra megjelölte), `dismissed` (a fiók félretette, nem foglalkozik vele). A `flagged` és a `dismissed` nem a válasz meglétéről szól, ezért a `response` és a `respondedAt` mezőt ezekkel az állapotokkal együtt is külön kell vizsgálni. A lista bővülhet, ismeretlen értékre is készülj fel."},"sentiment":{"type":["string","null"],"description":"A csillagszámból származtatott hangulat-címke, nem szövegelemzés: `pozitiv` (4-5 csillag), `semleges` (3 csillag), `negativ` (1-2 csillag). A `rating`-en túl nincs benne többletinformáció, Facebooknál pedig csak `pozitiv` vagy `negativ` lehet. `null` minden olyan értékelésnél, amely nem a Google- vagy Facebook-integráción át érkezett (kézi rögzítés, korábbi rendszerből átvett adat) - ezeknél a mező utólag sem töltődik ki, ne várj rá."},"createdAt":{"type":"string","format":"date-time","description":"Az értékelés keletkezésének időpontja UTC-ben. A korábbi rendszerből átvett értékeléseknél a forrás csak napra pontos dátumot ad, ezért az időpont-rész egységesen 12:00:00Z: ilyen soroknál csak a dátum megbízható, óránkénti bontásra, pontos idővonalra vagy szűk időablakos deduplikációra ne használd."}},"required":["id","platform","rating","content","customerName","contactId","response","respondedAt","status","sentiment","createdAt"]},"description":"A találatok az aktuális lapon, keletkezés szerint csökkenő sorrendben."},"limit":{"type":"integer","description":"A ténylegesen alkalmazott lapméret."},"offset":{"type":"integer","description":"Az alkalmazott eltolás. A következő laphoz add hozzá a `limit` értékét."}},"required":["reviews","limit","offset"]}}}},"400":{"description":"invalid_request: A séma-validáció bukott, vagy hiányzik egy kötelező paraméter. A `details[]` mezőnként sorolja fel az okot.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"401":{"description":"unauthorized: Hiányzó, hibás formátumú, ismeretlen, visszavont vagy lejárt token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"403":{"description":"forbidden: A token nem rendelkezik a szükséges scope-pal, a hívó IP nincs a kulcs allowlistáján, a fiók csomagja nem tartalmaz API-hozzáférést, vagy a fiók írás-tiltott (bemutató mód).","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"429":{"description":"rate_limited: A percalapú sebességkorlát (alapból 120 kérés/perc/kulcs) túllépve.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"500":{"description":"internal_error: Váratlan szerverhiba. Egyetlen végponton (`POST /contacts`) ugyanez a hiba a rövidebb `internal` kóddal érkezik - kezeld a kettőt azonosan.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}}}}},"/webhooks":{"post":{"operationId":"webhooks.create","tags":["webhooks"],"summary":"Webhook-feliratkozás létrehozása","description":"Az aláíró titkot az API kizárólag ebben a válaszban adja vissza; más API-végponton nem küldjük ki. Minden kézbesítés `X-Dynex-Signature` fejléce `sha256=` + HMAC-SHA256(titok, `<időbélyeg>.<nyers törzs>`) hexadecimálisan, ahol az `<időbélyeg>` az `X-Dynex-Timestamp` fejléc Unix-másodperc értéke - NEM a kézbesített törzs `timestamp` mezője, ami ISO-8601 alakú. Az aláírást mindig a nyers, feldolgozatlan törzsön ellenőrizd; mintakód a Webhookok fejezetben.\n\nSzükséges scope: `webhooks.manage`.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","format":"uri","description":"A cím, ahová a kézbesítéseket küldjük. Kizárólag `https://` fogadható el, felhasználónév és jelszó nélkül (`user:pass@` alak nem). A hosztnevet feloldjuk, és elutasítjuk, ha bármelyik feloldott cím magánhálózati vagy loopback cím; a fel nem oldható nevet is elutasítjuk (például ha a DNS-bejegyzés még nem propagált), ilyenkor `400 invalid_request` jön `url must be a public https address.` üzenettel. Ez az ellenőrzés nem csak mentéskor fut: minden kézbesítés előtt megismételjük, és a bukása hibás kézbesítésnek számít, tehát növeli a `consecutiveFailures` értékét. A címet mentés előtt normalizáljuk, és a válasz `url` mezőjében ez a normalizált alak jön vissza - nem feltétlenül karakterről karakterre az, amit beküldtél."},"events":{"type":"array","items":{},"minItems":1,"description":"Melyik eseményekre iratkozol fel. Az ismeretlen esemény-nevek csendben kiszűrődnek, az ismétlődések összevonódnak; ha a szűrés után egy név sem marad, `400` jön. `400` jön akkor is, ha a mező hiányzik, ha az értéke nem tömb, vagy ha üres tömb. Az elérhető eseményeket a Webhookok fejezet sorolja fel."},"description":{"description":"Belső megjegyzés, hogy később tudd, melyik integrációhoz tartozik ez a feliratkozás. A kézbesítésbe nem kerül bele."},"headers":{"type":"object","additionalProperties":{},"description":"Egyedi fejlécek, amiket a kézbesítésekkel elküldünk (például egy saját hitelesítő token). Emiatt sosem utasítjuk el a kérést, csak csendben igazítunk: az objektum első 10 bejegyzését tartjuk meg, a nem RFC 7230 token-nevű kulcsokat és a nem string típusú értékeket eldobjuk, az értékből a soremeléseket kitöröljük, a széli szóközöket levágjuk, és 1000 karakternél elvágjuk; az így üressé váló bejegyzés kimarad. A rendszer saját kézbesítési fejléceit (`Content-Type`, `Host`, `Content-Length`, `X-Dynex-Event`, `X-Dynex-Delivery-Id`, `X-Dynex-Timestamp`, `X-Dynex-Signature`) nem lehet felülírni: az ilyen nevű bejegyzés mentéskor elfogadható és a válaszban is visszakapod, de a kézbesítésből kimarad. A válasz `headers` objektumából ellenőrizd, mi rögzült ténylegesen."},"filters":{"type":"object","properties":{"reservationSources":{"description":"Csak ezekből a forrásokból származó foglalás-eseményeket kézbesítjük"},"pipelineIds":{"description":"Csak ezekhez a pipeline-okhoz tartozó üzlet-eseményeket kézbesítjük"},"reviewPlatforms":{"description":"Csak ezekről a platformokról érkező vélemény-eseményeket kézbesítjük"},"reviewMinRating":{"description":"Csak az ennél nem alacsonyabb értékelésű vélemény-eseményeket kézbesítjük"}},"description":"Szűrők, amikkel szűkítheted, mely események kézbesítődjenek. Elhagyva minden feliratkozott esemény kimegy."}},"required":["url","events"]}}}},"responses":{"201":{"description":"Sikeres válasz","content":{"application/json":{"schema":{"type":"object","properties":{"webhook":{"type":"object","properties":{"id":{"type":"string","description":"A feliratkozás azonosítója."},"url":{"type":"string","description":"A cím, ahová a kézbesítések mennek. Mindig https. A mentéskor normalizált alakot adjuk vissza, ami nem feltétlenül karakterről karakterre azonos a beküldöttel: a hosztnév kisbetűsödik, az üres útvonal `/`-re egészül ki, az alapértelmezett `:443` port eltűnik, az ékezetes domain pedig punycode alakra vált - például a `https://partner.example.com` `https://partner.example.com/` alakban jön vissza. Ha a beküldött címhez hasonlítod (deduplikáció, konfiguráció-eltérés figyelése), előbb a te oldaladon is normalizáld, ne bájtra egyeztess."},"events":{"type":"array","items":{"type":"string"},"description":"Melyik eseményekre szól a feliratkozás. Csak az itt felsorolt események kézbesítődnek erre a címre."},"headers":{"type":"object","additionalProperties":{"type":"string"},"description":"A feliratkozáshoz mentett egyedi fejlécek. Mindig objektum, üresen `{}`. A kézbesítésre ezek közül azok kerülnek rá, amelyek nem ütköznek a rendszer saját fejléceivel (`Content-Type`, `Host`, `Content-Length`, `X-Dynex-Event`, `X-Dynex-Delivery-Id`, `X-Dynex-Timestamp`, `X-Dynex-Signature`) - az ütköző nevű bejegyzést a mentés megőrzi és itt visszaadjuk, de a kézbesítésből kimarad."},"filters":{"type":["object","null"],"properties":{"reservationSources":{"type":"array","items":{"type":"string"},"description":"Csak az ezekből a forrásokból származó foglalás-események kézbesítődnek."},"pipelineIds":{"type":"array","items":{"type":"string"},"description":"Csak az ezekben a pipeline-okban lévő üzletek eseményei kézbesítődnek."},"reviewPlatforms":{"type":"array","items":{"type":"string"},"description":"Csak az ezekről a platformokról érkező értékelés-események kézbesítődnek."},"reviewMinRating":{"type":"integer","description":"Csak a legalább ennyi csillagos értékelések eseményei kézbesítődnek."}},"description":"Szűrők, amikkel a kézbesítés tovább szűkíthető. `null`, ha nincs szűrő - ilyenkor minden feliratkozott esemény kimegy. A szűrő nem szerepel valamennyi eseménytípuson: csak arra hat, amelyikre értelmezhető."},"description":{"type":["string","null"],"description":"Belső megjegyzés a feliratkozáshoz. A kézbesítésbe nem kerül bele, de ezt a mezőt minden `webhooks.manage` jogosultságú kulcs visszakapja ebben a válaszban."},"isActive":{"type":"boolean","description":"Aktív-e a feliratkozás. 20 egymást követő sikertelen kézbesítés után a rendszer magától kikapcsolja, és erre az API-n NINCS visszaút: módosító végpont nem létezik, visszakapcsolni csak a Dynex felületén (Beállítások > API) lehet, vagy a feliratkozás törlésével és újbóli létrehozásával - ami új azonosítót és új aláíró titkot jelent. Amíg `false`, a sorban álló kézbesítések véglegesen elvesznek (`dead` státuszt kapnak `subscription inactive` hibával), az automatikus újrapróbálkozás sem hozza vissza őket. Ezért figyeld a `consecutiveFailures` mezőt, mielőtt eléri a 20-at."},"consecutiveFailures":{"type":"integer","description":"Hány kézbesítés bukott el egymás után. Sikeres kézbesítéskor nullázódik. Ha ez tartósan nő, a végpontod nem fogadja el a hívásokat."},"lastSuccessAt":{"type":["string","null"],"format":"date-time","description":"Az utolsó sikeres kézbesítés időpontja UTC-ben. `null`, ha még sosem sikerült."},"lastFailureAt":{"type":["string","null"],"format":"date-time","description":"Az utolsó sikertelen kézbesítés időpontja UTC-ben. `null`, ha még sosem bukott el."},"createdAt":{"type":"string","format":"date-time","description":"A feliratkozás létrejöttének időpontja UTC-ben."}},"required":["id","url","events","headers","filters","description","isActive","consecutiveFailures","lastSuccessAt","lastFailureAt","createdAt"]},"secret":{"type":"string","description":"Az aláíró titok. Az API ezt kizárólag itt, a létrehozás válaszában adja vissza. Tedd el biztonságos helyre: ezzel tudod ellenőrizni, hogy a beérkező kézbesítés tényleg tőlünk jött. Ha elvesztetted, a Dynex felületén (Beállítások > API) újra megnézheted, vagy új titkot generálhatsz a feliratkozás törlése nélkül."}},"required":["webhook","secret"]}}}},"400":{"description":"invalid_request: A séma-validáció bukott, vagy hiányzik egy kötelező paraméter. A `details[]` mezőnként sorolja fel az okot.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"401":{"description":"unauthorized: Hiányzó, hibás formátumú, ismeretlen, visszavont vagy lejárt token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"403":{"description":"forbidden: A token nem rendelkezik a szükséges scope-pal, a hívó IP nincs a kulcs allowlistáján, a fiók csomagja nem tartalmaz API-hozzáférést, vagy a fiók írás-tiltott (bemutató mód).","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"429":{"description":"rate_limited: A percalapú sebességkorlát (alapból 120 kérés/perc/kulcs) túllépve.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"500":{"description":"internal_error: Váratlan szerverhiba. Egyetlen végponton (`POST /contacts`) ugyanez a hiba a rövidebb `internal` kóddal érkezik - kezeld a kettőt azonosan.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}}}},"get":{"operationId":"webhooks.list","tags":["webhooks"],"summary":"Webhook-feliratkozások listázása","description":"A fiók összes webhook-feliratkozása. Az aláíró titok itt nem szerepel a válaszban - azt az API kizárólag a létrehozáskor adja vissza. Ha elvesztetted, NE töröld a feliratkozást: a titok a Dynex felületén (Beállítások > API) bármikor megnézhető, és törlés nélkül újragenerálható, a feliratkozás azonosítójának és kézbesítési előzményének megtartásával. A `consecutiveFailures` és a `lastFailureAt` mezőből látod, ha a végpontod nem fogadja a kézbesítéseket.\n\nSzükséges scope: `webhooks.manage`.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Sikeres válasz","content":{"application/json":{"schema":{"type":"object","properties":{"webhooks":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"A feliratkozás azonosítója."},"url":{"type":"string","description":"A cím, ahová a kézbesítések mennek. Mindig https. A mentéskor normalizált alakot adjuk vissza, ami nem feltétlenül karakterről karakterre azonos a beküldöttel: a hosztnév kisbetűsödik, az üres útvonal `/`-re egészül ki, az alapértelmezett `:443` port eltűnik, az ékezetes domain pedig punycode alakra vált - például a `https://partner.example.com` `https://partner.example.com/` alakban jön vissza. Ha a beküldött címhez hasonlítod (deduplikáció, konfiguráció-eltérés figyelése), előbb a te oldaladon is normalizáld, ne bájtra egyeztess."},"events":{"type":"array","items":{"type":"string"},"description":"Melyik eseményekre szól a feliratkozás. Csak az itt felsorolt események kézbesítődnek erre a címre."},"headers":{"type":"object","additionalProperties":{"type":"string"},"description":"A feliratkozáshoz mentett egyedi fejlécek. Mindig objektum, üresen `{}`. A kézbesítésre ezek közül azok kerülnek rá, amelyek nem ütköznek a rendszer saját fejléceivel (`Content-Type`, `Host`, `Content-Length`, `X-Dynex-Event`, `X-Dynex-Delivery-Id`, `X-Dynex-Timestamp`, `X-Dynex-Signature`) - az ütköző nevű bejegyzést a mentés megőrzi és itt visszaadjuk, de a kézbesítésből kimarad."},"filters":{"type":["object","null"],"properties":{"reservationSources":{"type":"array","items":{"type":"string"},"description":"Csak az ezekből a forrásokból származó foglalás-események kézbesítődnek."},"pipelineIds":{"type":"array","items":{"type":"string"},"description":"Csak az ezekben a pipeline-okban lévő üzletek eseményei kézbesítődnek."},"reviewPlatforms":{"type":"array","items":{"type":"string"},"description":"Csak az ezekről a platformokról érkező értékelés-események kézbesítődnek."},"reviewMinRating":{"type":"integer","description":"Csak a legalább ennyi csillagos értékelések eseményei kézbesítődnek."}},"description":"Szűrők, amikkel a kézbesítés tovább szűkíthető. `null`, ha nincs szűrő - ilyenkor minden feliratkozott esemény kimegy. A szűrő nem szerepel valamennyi eseménytípuson: csak arra hat, amelyikre értelmezhető."},"description":{"type":["string","null"],"description":"Belső megjegyzés a feliratkozáshoz. A kézbesítésbe nem kerül bele, de ezt a mezőt minden `webhooks.manage` jogosultságú kulcs visszakapja ebben a válaszban."},"isActive":{"type":"boolean","description":"Aktív-e a feliratkozás. 20 egymást követő sikertelen kézbesítés után a rendszer magától kikapcsolja, és erre az API-n NINCS visszaút: módosító végpont nem létezik, visszakapcsolni csak a Dynex felületén (Beállítások > API) lehet, vagy a feliratkozás törlésével és újbóli létrehozásával - ami új azonosítót és új aláíró titkot jelent. Amíg `false`, a sorban álló kézbesítések véglegesen elvesznek (`dead` státuszt kapnak `subscription inactive` hibával), az automatikus újrapróbálkozás sem hozza vissza őket. Ezért figyeld a `consecutiveFailures` mezőt, mielőtt eléri a 20-at."},"consecutiveFailures":{"type":"integer","description":"Hány kézbesítés bukott el egymás után. Sikeres kézbesítéskor nullázódik. Ha ez tartósan nő, a végpontod nem fogadja el a hívásokat."},"lastSuccessAt":{"type":["string","null"],"format":"date-time","description":"Az utolsó sikeres kézbesítés időpontja UTC-ben. `null`, ha még sosem sikerült."},"lastFailureAt":{"type":["string","null"],"format":"date-time","description":"Az utolsó sikertelen kézbesítés időpontja UTC-ben. `null`, ha még sosem bukott el."},"createdAt":{"type":"string","format":"date-time","description":"A feliratkozás létrejöttének időpontja UTC-ben."}},"required":["id","url","events","headers","filters","description","isActive","consecutiveFailures","lastSuccessAt","lastFailureAt","createdAt"]},"description":"A feliratkozások. Nem lapozható, mert egy fiókon jellemzően néhány feliratkozás van."}},"required":["webhooks"]}}}},"401":{"description":"unauthorized: Hiányzó, hibás formátumú, ismeretlen, visszavont vagy lejárt token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"403":{"description":"forbidden: A token nem rendelkezik a szükséges scope-pal, a hívó IP nincs a kulcs allowlistáján, a fiók csomagja nem tartalmaz API-hozzáférést, vagy a fiók írás-tiltott (bemutató mód).","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"429":{"description":"rate_limited: A percalapú sebességkorlát (alapból 120 kérés/perc/kulcs) túllépve.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"500":{"description":"internal_error: Váratlan szerverhiba. Egyetlen végponton (`POST /contacts`) ugyanez a hiba a rövidebb `internal` kóddal érkezik - kezeld a kettőt azonosan.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}}}}},"/webhooks/{id}":{"delete":{"operationId":"webhooks.delete","tags":["webhooks"],"summary":"Webhook-feliratkozás törlése","description":"Véglegesen törli a feliratkozást, és ezzel az aláíró titkot is - a törlés után erre a címre nem megy több kézbesítés. A feliratkozás kézbesítési előzménye és a még függőben lévő kézbesítései is elvesznek, egy újonnan létrehozott feliratkozás pedig új azonosítót és új titkot kap. Ha csak átmenetileg állítanád le, ne törölj: az API-ból kikapcsolni valóban nem lehet, de a Dynex felületén (Beállítások > API) a feliratkozás szüneteltethető, majd ugyanazzal az azonosítóval és titokkal visszakapcsolható.\n\nSzükséges scope: `webhooks.manage`.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Erőforrás-azonosító"},"required":true,"description":"Erőforrás-azonosító","name":"id","in":"path"}],"responses":{"200":{"description":"Sikeres válasz","content":{"application/json":{"schema":{"type":"object","properties":{"deleted":{"type":"boolean","enum":[true],"description":"Mindig `true`, ha a törlés megtörtént."},"id":{"type":"string","description":"A törölt feliratkozás azonosítója."}},"required":["deleted","id"]}}}},"401":{"description":"unauthorized: Hiányzó, hibás formátumú, ismeretlen, visszavont vagy lejárt token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"403":{"description":"forbidden: A token nem rendelkezik a szükséges scope-pal, a hívó IP nincs a kulcs allowlistáján, a fiók csomagja nem tartalmaz API-hozzáférést, vagy a fiók írás-tiltott (bemutató mód).","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"404":{"description":"not_found: Az erőforrás nem létezik EBBEN a fiókban. Egy másik fiókhoz tartozó azonosító is ezt adja - a kettő szándékosan megkülönböztethetetlen.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"429":{"description":"rate_limited: A percalapú sebességkorlát (alapból 120 kérés/perc/kulcs) túllépve.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"500":{"description":"internal_error: Váratlan szerverhiba. Egyetlen végponton (`POST /contacts`) ugyanez a hiba a rövidebb `internal` kóddal érkezik - kezeld a kettőt azonosan.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}}}},"get":{"operationId":"webhooks.get","tags":["webhooks"],"summary":"Egy webhook-feliratkozás lekérdezése","description":"Egyetlen feliratkozás állapota azonosító alapján. Innen olvasható ki, hogy aktív-e, és hogy sikerülnek-e a kézbesítések. Az aláíró titkot ez a végpont sem adja vissza.\n\nSzükséges scope: `webhooks.manage`.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Erőforrás-azonosító"},"required":true,"description":"Erőforrás-azonosító","name":"id","in":"path"}],"responses":{"200":{"description":"Sikeres válasz","content":{"application/json":{"schema":{"type":"object","properties":{"webhook":{"type":"object","properties":{"id":{"type":"string","description":"A feliratkozás azonosítója."},"url":{"type":"string","description":"A cím, ahová a kézbesítések mennek. Mindig https. A mentéskor normalizált alakot adjuk vissza, ami nem feltétlenül karakterről karakterre azonos a beküldöttel: a hosztnév kisbetűsödik, az üres útvonal `/`-re egészül ki, az alapértelmezett `:443` port eltűnik, az ékezetes domain pedig punycode alakra vált - például a `https://partner.example.com` `https://partner.example.com/` alakban jön vissza. Ha a beküldött címhez hasonlítod (deduplikáció, konfiguráció-eltérés figyelése), előbb a te oldaladon is normalizáld, ne bájtra egyeztess."},"events":{"type":"array","items":{"type":"string"},"description":"Melyik eseményekre szól a feliratkozás. Csak az itt felsorolt események kézbesítődnek erre a címre."},"headers":{"type":"object","additionalProperties":{"type":"string"},"description":"A feliratkozáshoz mentett egyedi fejlécek. Mindig objektum, üresen `{}`. A kézbesítésre ezek közül azok kerülnek rá, amelyek nem ütköznek a rendszer saját fejléceivel (`Content-Type`, `Host`, `Content-Length`, `X-Dynex-Event`, `X-Dynex-Delivery-Id`, `X-Dynex-Timestamp`, `X-Dynex-Signature`) - az ütköző nevű bejegyzést a mentés megőrzi és itt visszaadjuk, de a kézbesítésből kimarad."},"filters":{"type":["object","null"],"properties":{"reservationSources":{"type":"array","items":{"type":"string"},"description":"Csak az ezekből a forrásokból származó foglalás-események kézbesítődnek."},"pipelineIds":{"type":"array","items":{"type":"string"},"description":"Csak az ezekben a pipeline-okban lévő üzletek eseményei kézbesítődnek."},"reviewPlatforms":{"type":"array","items":{"type":"string"},"description":"Csak az ezekről a platformokról érkező értékelés-események kézbesítődnek."},"reviewMinRating":{"type":"integer","description":"Csak a legalább ennyi csillagos értékelések eseményei kézbesítődnek."}},"description":"Szűrők, amikkel a kézbesítés tovább szűkíthető. `null`, ha nincs szűrő - ilyenkor minden feliratkozott esemény kimegy. A szűrő nem szerepel valamennyi eseménytípuson: csak arra hat, amelyikre értelmezhető."},"description":{"type":["string","null"],"description":"Belső megjegyzés a feliratkozáshoz. A kézbesítésbe nem kerül bele, de ezt a mezőt minden `webhooks.manage` jogosultságú kulcs visszakapja ebben a válaszban."},"isActive":{"type":"boolean","description":"Aktív-e a feliratkozás. 20 egymást követő sikertelen kézbesítés után a rendszer magától kikapcsolja, és erre az API-n NINCS visszaút: módosító végpont nem létezik, visszakapcsolni csak a Dynex felületén (Beállítások > API) lehet, vagy a feliratkozás törlésével és újbóli létrehozásával - ami új azonosítót és új aláíró titkot jelent. Amíg `false`, a sorban álló kézbesítések véglegesen elvesznek (`dead` státuszt kapnak `subscription inactive` hibával), az automatikus újrapróbálkozás sem hozza vissza őket. Ezért figyeld a `consecutiveFailures` mezőt, mielőtt eléri a 20-at."},"consecutiveFailures":{"type":"integer","description":"Hány kézbesítés bukott el egymás után. Sikeres kézbesítéskor nullázódik. Ha ez tartósan nő, a végpontod nem fogadja el a hívásokat."},"lastSuccessAt":{"type":["string","null"],"format":"date-time","description":"Az utolsó sikeres kézbesítés időpontja UTC-ben. `null`, ha még sosem sikerült."},"lastFailureAt":{"type":["string","null"],"format":"date-time","description":"Az utolsó sikertelen kézbesítés időpontja UTC-ben. `null`, ha még sosem bukott el."},"createdAt":{"type":"string","format":"date-time","description":"A feliratkozás létrejöttének időpontja UTC-ben."}},"required":["id","url","events","headers","filters","description","isActive","consecutiveFailures","lastSuccessAt","lastFailureAt","createdAt"]}},"required":["webhook"]}}}},"401":{"description":"unauthorized: Hiányzó, hibás formátumú, ismeretlen, visszavont vagy lejárt token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"403":{"description":"forbidden: A token nem rendelkezik a szükséges scope-pal, a hívó IP nincs a kulcs allowlistáján, a fiók csomagja nem tartalmaz API-hozzáférést, vagy a fiók írás-tiltott (bemutató mód).","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"404":{"description":"not_found: Az erőforrás nem létezik EBBEN a fiókban. Egy másik fiókhoz tartozó azonosító is ezt adja - a kettő szándékosan megkülönböztethetetlen.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"429":{"description":"rate_limited: A percalapú sebességkorlát (alapból 120 kérés/perc/kulcs) túllépve.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"500":{"description":"internal_error: Váratlan szerverhiba. Egyetlen végponton (`POST /contacts`) ugyanez a hiba a rövidebb `internal` kóddal érkezik - kezeld a kettőt azonosan.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}}}}},"/conversions":{"post":{"operationId":"conversions.send","tags":["conversions"],"summary":"Konverziós esemény küldése (Meta CAPI / GA4 / TikTok)","description":"Szerveroldali konverzió a bérlő Követés-beállításai szerint. Alapból csak hirdetés-kattintásból érkező eseményt továbbítunk, és mindegyiket csak a saját platformjára: `fbclid` a Meta CAPI-ba, `gclid` a GA4-be, `ttclid` a TikTok Events API-ba (több azonosító együtt több platformra megy). A `force: true` vagy a bérlő „minden forgalom” beállítása ezt felülírja: ilyenkor kattintás-azonosító nélkül is, és minden bekötött platformra elmegy az esemény. Nem minden mezőt kap meg minden platform: a nevet, a települést és az irányítószámot csak a Meta CAPI, az e-mailt és a telefonszámot a Meta CAPI és a TikTok; a GA4 Measurement Protocol felé felhasználói adatot egyáltalán nem továbbítunk. A közvetlen azonosítókat - e-mail, telefonszám, kereszt- és vezetéknév, település, irányítószám - SHA-256 kivonatként küldjük tovább; a `clientIp` és a `userAgent` ezzel szemben kivonatolás nélkül, nyersen jut el a Metához és a TikTokhoz. Ezt vedd figyelembe a saját adatkezelési tájékoztatód elkészítésekor.\n\nSzükséges scope: `conversions.write`.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"eventName":{"type":"string","enum":["ViewContent","Lead","Purchase"],"description":"Melyik konverziós esemény történt. `ViewContent`: a látogató megnézett egy oldalt vagy terméket. `Lead`: érdeklődést hagyott (űrlap, foglalás). `Purchase`: vásárlás vagy fizetés történt. Figyelem: az esemény a platformokon eltérő néven jelenik meg. A Metára változatlan névvel megy (`ViewContent` / `Lead` / `Purchase`), a GA4-be `view_item` / `generate_lead` / `purchase`, a TikTokba `ViewContent` / `SubmitForm` / `CompletePayment` néven. Az ellenőrzésnél (GA4 DebugView, TikTok Events Manager) ezeket a neveket keresd, ne az itt megadott értéket."},"eventId":{"type":"string","maxLength":120,"description":"Deduplikációs azonosító a Meta és a TikTok felé. Ugyanazt az értéket add meg itt és a böngészőben futó Meta/TikTok pixelnek, hogy a platform ne számolja duplán a szerver- és a kliensoldali eseményt. A GA4 Measurement Protocol felé nem küldünk esemény-azonosítót, ott a szerver- és a kliensoldali esemény külön számít; a GA4 az itt megadott értéket `client_id`-ként kapja meg, ezért eseményenként külön felhasználónak látja a küldést. Elhagyva a rendszer generál egyet, de akkor a Meta/TikTok deduplikáció sem működik."},"email":{"type":"string","format":"email","description":"A látogató e-mail címe. Küldés előtt SHA-256 kivonattá alakítjuk, a nyers cím sosem hagyja el a rendszert. A Meta CAPI és a TikTok kapja meg, a GA4 nem."},"phone":{"type":"string","maxLength":40,"description":"A látogató telefonszáma. Küldés előtt SHA-256 kivonattá alakítjuk. A Meta CAPI és a TikTok kapja meg, a GA4 nem."},"firstName":{"type":"string","maxLength":80,"description":"A látogató keresztneve. Küldés előtt SHA-256 kivonattá alakítjuk. Csak a Meta CAPI kapja meg - a GA4 és a TikTok felé nem továbbítjuk, ott nem javítja a párosítást."},"lastName":{"type":"string","maxLength":80,"description":"A látogató vezetékneve. Küldés előtt SHA-256 kivonattá alakítjuk. Csak a Meta CAPI kapja meg - a GA4 és a TikTok felé nem továbbítjuk."},"city":{"type":"string","maxLength":80,"description":"A látogató települése. Küldés előtt SHA-256 kivonattá alakítjuk. Csak a Meta CAPI kapja meg - a GA4 és a TikTok felé nem továbbítjuk."},"zip":{"type":"string","maxLength":12,"description":"A látogató irányítószáma. Küldés előtt SHA-256 kivonattá alakítjuk. Csak a Meta CAPI kapja meg - a GA4 és a TikTok felé nem továbbítjuk."},"value":{"type":"number","minimum":0,"description":"Az esemény pénzben kifejezett értéke. `Purchase` eseménynél a bevétel, `Lead` eseménynél a becsült érték. Nem lehet negatív."},"currency":{"type":"string","minLength":3,"maxLength":3,"description":"Az érték pénzneme, pontosan három betűs kód. Alapértelmezés `HUF`."},"fbclid":{"type":"string","maxLength":400,"description":"A Meta hirdetés-kattintás azonosítója a beérkező URL-ből. Ez köti az eseményt a hirdetéshez, és egyben ez irányítja a Meta CAPI-ba: `force` nélkül csak akkor megy esemény a Metába, ha ezt megadod."},"gclid":{"type":"string","maxLength":400,"description":"A Google Ads kattintás-azonosítója a beérkező URL-ből. `force` nélkül csak akkor továbbítjuk az eseményt a GA4-be, ha ezt megadod. Az értéket magát nem küldjük tovább, csak a platform kiválasztására használjuk."},"ttclid":{"type":"string","maxLength":400,"description":"A TikTok kattintás-azonosítója a beérkező URL-ből. `force` nélkül csak akkor továbbítjuk az eseményt a TikTok Events API-ba, ha ezt megadod."},"sourceUrl":{"type":"string","format":"uri","description":"Annak az oldalnak a teljes címe, ahol az esemény történt."},"contentName":{"type":"string","maxLength":120,"description":"Mire vonatkozik az esemény (például a megnézett termék vagy oldal neve)."},"clientIp":{"type":"string","maxLength":64,"description":"A látogató (böngésző) IP-címe. Az eseményt a Dynex szervere továbbítja a platformokra, ezért a látogató címét csak akkor ismerjük, ha itt megadod; elhagyva a Meta és a TikTok felé IP nélkül megy ki az esemény, és romlik a párosítás. A GA4 felé IP-t egyáltalán nem továbbítunk. Figyelem: ez a mező kivonatolás nélkül, nyersen kerül a Meta és a TikTok rendszerébe."},"userAgent":{"type":"string","maxLength":400,"description":"A látogató böngésző-azonosítója. Ugyanazért fontos, mint a `clientIp`: nélküle a Meta és a TikTok felé kimarad a törzsből, a GA4-be pedig sosem továbbítjuk. Ugyanúgy kivonatolás nélkül, nyersen megy ki."},"force":{"type":"boolean","description":"`true` esetén kattintás-azonosító nélkül is továbbítjuk az eseményt, és ilyenkor minden bekötött platformra kimegy (Meta, GA4, TikTok), nem csak arra, amelyiknek a kattintás-azonosítóját megadtad. Alapból csak a hirdetésből érkező forgalmat továbbítjuk, és csak a hozzá tartozó platformra."}},"required":["eventName"]}}}},"responses":{"202":{"description":"Sikeres válasz","content":{"application/json":{"schema":{"type":"object","properties":{"accepted":{"type":"boolean","enum":[true],"description":"Mindig `true`. A `202` az esemény átvételét jelenti, nem a hirdetési platform visszaigazolását, és nem is garancia arra, hogy az eseményt egyáltalán továbbítottuk (lásd a figyelmeztetéseket)."},"eventId":{"type":"string","description":"Az esemény deduplikációs azonosítója a Meta és a TikTok felé. Ha nem adtál meg sajátot, itt kapod meg a generáltat. Az azonosítót a Dynex nem tárolja el: kizárólag a hirdetési platformok deduplikációjához használjuk, utólag nem lehet vele az eseményre rákeresni."}},"required":["accepted","eventId"]}}}},"400":{"description":"invalid_request: A séma-validáció bukott, vagy hiányzik egy kötelező paraméter. A `details[]` mezőnként sorolja fel az okot.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"401":{"description":"unauthorized: Hiányzó, hibás formátumú, ismeretlen, visszavont vagy lejárt token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"403":{"description":"forbidden: A token nem rendelkezik a szükséges scope-pal, a hívó IP nincs a kulcs allowlistáján, a fiók csomagja nem tartalmaz API-hozzáférést, vagy a fiók írás-tiltott (bemutató mód).","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"429":{"description":"rate_limited: A percalapú sebességkorlát (alapból 120 kérés/perc/kulcs) túllépve.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"500":{"description":"internal_error: Váratlan szerverhiba. Egyetlen végponton (`POST /contacts`) ugyanez a hiba a rövidebb `internal` kóddal érkezik - kezeld a kettőt azonosan.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}}}}},"/tracking-config":{"get":{"operationId":"conversions.tracking_config","tags":["conversions"],"summary":"Kliensoldali követő-konfig (GTM, Pixel ID-k) a saját oldalhoz","description":"A saját weboldaladba építhető követő-azonosítók, hogy ne kelljen kézzel átmásolnod őket a Dynex beállításaiból. Csak PUBLIKUS azonosítókat ad vissza - a szerveroldali hozzáférési tokenek soha nem szerepelnek benne, ezért a VÁLASZ értékei nyugodtan kikerülhetnek a böngészőbe kiszolgált oldalra. Kikapcsolt követésnél minden azonosító `null` (az esemény-kapcsolók a beállított értéküket adják vissza ilyenkor is). A hívás a `conversions.write` scope-ot kéri, mert ugyanahhoz az integrációhoz tartozik, mint az esemény-küldés.\n\nSzükséges scope: `conversions.write`.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Sikeres válasz","content":{"application/json":{"schema":{"type":"object","properties":{"enabled":{"type":"boolean","description":"Be van-e kapcsolva a követés a fiókon. Ha `false`, a `POST /conversions` egyetlen platformra sem küld eseményt - akkor sem, ha egyébként minden azonosító ki van töltve -, mert kikapcsolt követésnél az azonosítókat sem adjuk ki. Ezért ha minden azonosító `null`, ebből a mezőből tudod meg, mi a teendő: `false` esetén a követést kell bekapcsolni, `true` esetén az azonosítókat kitölteni. Mindkettő a Dynex kezelőfelületén, az Asztalfoglalás modul Követés / Pixel fülén."},"gtmContainerId":{"type":["string","null"],"description":"A Google Tag Manager konténer azonosítója (`GTM-` kezdetű). `null`, ha a fiók nem használ konténert, VAGY ha a követés ki van kapcsolva - lásd az `enabled` mezőt."},"fbPixelId":{"type":["string","null"],"description":"A Meta pixel azonosítója. `null`, ha nincs beállítva, VAGY ha a követés ki van kapcsolva - lásd az `enabled` mezőt."},"googleMeasurementId":{"type":["string","null"],"description":"A Google Analytics 4 mérési azonosítója (`G-` kezdetű). `null`, ha nincs beállítva, VAGY ha a követés ki van kapcsolva - lásd az `enabled` mezőt."},"tiktokPixelId":{"type":["string","null"],"description":"A TikTok pixel azonosítója. `null`, ha nincs beállítva, VAGY ha a követés ki van kapcsolva - lásd az `enabled` mezőt."},"events":{"type":"object","properties":{"viewContent":{"type":"boolean","description":"Küldjön-e a kliensoldali pixel `ViewContent` eseményt."},"lead":{"type":"boolean","description":"Küldjön-e a kliensoldali pixel `Lead` eseményt."},"purchase":{"type":"boolean","description":"Küldjön-e a kliensoldali pixel `Purchase` eseményt."}},"required":["viewContent","lead","purchase"]}},"required":["enabled","gtmContainerId","fbPixelId","googleMeasurementId","tiktokPixelId","events"]}}}},"401":{"description":"unauthorized: Hiányzó, hibás formátumú, ismeretlen, visszavont vagy lejárt token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"403":{"description":"forbidden: A token nem rendelkezik a szükséges scope-pal, a hívó IP nincs a kulcs allowlistáján, a fiók csomagja nem tartalmaz API-hozzáférést, vagy a fiók írás-tiltott (bemutató mód).","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"429":{"description":"rate_limited: A percalapú sebességkorlát (alapból 120 kérés/perc/kulcs) túllépve.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"500":{"description":"internal_error: Váratlan szerverhiba. Egyetlen végponton (`POST /contacts`) ugyanez a hiba a rövidebb `internal` kóddal érkezik - kezeld a kettőt azonosan.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}}}}},"/content/authors":{"get":{"operationId":"content.authors","tags":["content"],"summary":"Blog-szerzők listázása","description":"A fiók blog-szerzői (név, arckép, bemutatkozás), lapozás nélkül. Tájékoztató lista: szerzőt létrehozni nem lehet, és a poszt `authorName` mezője sem köti a posztot ezekhez a szerzőkhöz.\n\nSzükséges scope: `content.readonly`.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Csak ennek a weboldalnak a szerzői. A fiókhoz nem tartozó azonosítóra `422 unprocessable` a válasz, nem üres lista. Elhagyva a fiók összes weboldala."},"required":false,"description":"Csak ennek a weboldalnak a szerzői. A fiókhoz nem tartozó azonosítóra `422 unprocessable` a válasz, nem üres lista. Elhagyva a fiók összes weboldala.","name":"websiteId","in":"query"}],"responses":{"200":{"description":"Sikeres válasz","content":{"application/json":{"schema":{"type":"object","properties":{"authors":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"A szerző azonosítója."},"name":{"type":"string","description":"A szerző neve."},"avatarUrl":{"type":["string","null"],"description":"Az arckép címe; `null`, ha nincs."},"bio":{"type":["string","null"],"description":"Rövid bemutatkozás; `null`, ha nincs."}},"required":["id","name","avatarUrl","bio"]},"description":"A szerzők betűrendben."}},"required":["authors"]}}}},"400":{"description":"invalid_request: A séma-validáció bukott, vagy hiányzik egy kötelező paraméter. A `details[]` mezőnként sorolja fel az okot.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"401":{"description":"unauthorized: Hiányzó, hibás formátumú, ismeretlen, visszavont vagy lejárt token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"403":{"description":"forbidden: A token nem rendelkezik a szükséges scope-pal, a hívó IP nincs a kulcs allowlistáján, a fiók csomagja nem tartalmaz API-hozzáférést, vagy a fiók írás-tiltott (bemutató mód).","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"422":{"description":"unprocessable: Formailag helyes kérés, amit egy üzleti szabály utasít el. A blog-végpontokon: a megadott `websiteId` nem a fiók weboldala, vagy a fióknak még egyetlen weboldala sincs.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"429":{"description":"rate_limited: A percalapú sebességkorlát (alapból 120 kérés/perc/kulcs) túllépve.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"500":{"description":"internal_error: Váratlan szerverhiba. Egyetlen végponton (`POST /contacts`) ugyanez a hiba a rövidebb `internal` kóddal érkezik - kezeld a kettőt azonosan.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}}}}},"/content/categories":{"get":{"operationId":"content.categories","tags":["content"],"summary":"Blog-kategóriák listázása poszt-számmal","description":"A fiók blog-kategóriái a posztszámmal, lapozás nélkül. Poszt beküldésekor az innen kapott `slug` garantáltan meglévő kategóriára illeszkedik. Kategóriát létrehozni és törölni ezen az API-n nem lehet.\n\nSzükséges scope: `content.readonly`.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Csak ennek a weboldalnak a kategóriái. A fiókhoz nem tartozó azonosítóra `422 unprocessable` a válasz, nem üres lista. Elhagyva a fiók összes weboldala."},"required":false,"description":"Csak ennek a weboldalnak a kategóriái. A fiókhoz nem tartozó azonosítóra `422 unprocessable` a válasz, nem üres lista. Elhagyva a fiók összes weboldala.","name":"websiteId","in":"query"}],"responses":{"200":{"description":"Sikeres válasz","content":{"application/json":{"schema":{"type":"object","properties":{"categories":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"A kategória azonosítója."},"name":{"type":"string","description":"A kategória neve."},"slug":{"type":"string","description":"A kategória slugja - poszt beküldésekor ezt küldd a `category` mezőben."},"description":{"type":["string","null"],"description":"A kategória leírása; az API-n keletkezett kategóriáknál `null`."},"postCount":{"type":"integer","description":"A kategória posztjainak száma, minden állapotot beleértve."}},"required":["id","name","slug","description","postCount"]},"description":"A kategóriák betűrendben."}},"required":["categories"]}}}},"400":{"description":"invalid_request: A séma-validáció bukott, vagy hiányzik egy kötelező paraméter. A `details[]` mezőnként sorolja fel az okot.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"401":{"description":"unauthorized: Hiányzó, hibás formátumú, ismeretlen, visszavont vagy lejárt token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"403":{"description":"forbidden: A token nem rendelkezik a szükséges scope-pal, a hívó IP nincs a kulcs allowlistáján, a fiók csomagja nem tartalmaz API-hozzáférést, vagy a fiók írás-tiltott (bemutató mód).","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"422":{"description":"unprocessable: Formailag helyes kérés, amit egy üzleti szabály utasít el. A blog-végpontokon: a megadott `websiteId` nem a fiók weboldala, vagy a fióknak még egyetlen weboldala sincs.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"429":{"description":"rate_limited: A percalapú sebességkorlát (alapból 120 kérés/perc/kulcs) túllépve.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"500":{"description":"internal_error: Váratlan szerverhiba. Egyetlen végponton (`POST /contacts`) ugyanez a hiba a rövidebb `internal` kóddal érkezik - kezeld a kettőt azonosan.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}}}}},"/content/posts":{"post":{"operationId":"content.create","tags":["content"],"summary":"Blogposzt létrehozása","description":"Új blogposztot hoz létre a fiók egyik weboldalán, azonnali mentéssel. Kötelező a `title`, és a `contentHtml` vagy a `rawHtml` mezőben a HTML törzs. A válasz a poszt azonosítóját, VÉGLEGES slugját, nyilvános címét és állapotát adja; a teljes alakot a `GET /content/posts/{id}` adja vissza. Módosító és törlő végpont nincs: egy hibásan beküldött posztot csak a Dynex felületén lehet javítani.\n\nSzükséges scope: `content.write`.\n\nTámogatja az `Idempotency-Key` fejlécet.\n\nA `contentHtml` és `rawHtml` mező közül legalább egyet el kell küldeni. Külön-külön mindegyik elhagyható - a „vagy\" kapcsolatot a séma nem tudja kifejezni -, de ha egyiket sem küldöd, a válasz 400.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string","minLength":1,"description":"A poszt címe. A szélső szóközök levágódnak, a csak szóközből álló cím `400`-at ad. Slug hiányában ebből képződik az URL."},"contentHtml":{"type":"string","description":"A poszt HTML törzse. A `rawHtml`-lel együtt kötelező pár: legalább az egyiknek nem üres HTML-t kell tartalmaznia. A rendszer nem tisztítja és nem alakítja át."},"rawHtml":{"type":"string","description":"A `contentHtml` másik neve. Csak akkor számít, ha a `contentHtml` kulcs egyáltalán nincs a törzsben."},"description":{"type":"string","description":"A bevezető másik neve: akkor kerül az `excerpt` mezőbe, ha az `excerpt` kulcs hiányzik."},"excerpt":{"type":"string","description":"Rövid bevezető a listaoldalakhoz. Elsőbbsége van a `description` mezővel szemben. Nem generálódik a törzsből."},"coverImageUrl":{"type":"string","format":"uri","description":"A borítókép nyilvános címe, kötelezően `https://` kezdettel. A másolás feltételeit lásd fent."},"slug":{"type":"string","description":"A kívánt URL-részlet. Ugyanúgy átalakul, mint a cím (kisbetű, ékezet nélkül, kötőjelek), és ütközéskor toldalékot kap - a végleges értéket a válaszból olvasd."},"tags":{"type":"array","items":{"type":"string"},"description":"A poszt címkéi, szabad szövegként. A lista `tag` szűrője betű szerint pontos egyezéssel keres rájuk."},"category":{"type":"string","minLength":1,"description":"A kategória neve vagy slugja a cél-weboldalon. Ha nem létezik, a rendszer LÉTREHOZZA."},"authorName":{"type":"string","description":"A szerző neve szabad szövegként. Nem köti a posztot a `GET /content/authors` szerzőihez."},"status":{"type":"string","enum":["draft","published","scheduled"],"description":"Kezdő állapot, alapértelmezés `draft`. A `published` azonnal nyilvános. A `scheduled` mellé a `scheduledFor` kötelező, különben `400 invalid_request`."},"publishedAt":{"type":"string","description":"Megjelenítési dátum, nem kapcsoló. Elhagyva a `published` poszt a létrehozás pillanatát kapja."},"scheduledFor":{"type":"string","description":"Az ütemezett megjelenés időpontja; a `scheduled` státuszhoz kötelező. A múltbeli időpont azonnal élővé teszi a posztot."},"websiteId":{"type":"string","description":"A cél-weboldal azonosítója (a `GET /content/posts/{id}` válaszában vagy a Dynex felületén található). Más fiók weboldalára, illetve weboldal nélküli fióknál `422 unprocessable`."},"seo":{"type":"object","properties":{"title":{"type":"string","description":"A keresőkben és a megosztás-előnézetben mutatott cím."},"description":{"type":"string","description":"A keresőkben mutatott rövid leírás."}},"description":"SEO-mezők. Más kulcsok csendben kimaradnak."}},"required":["title"],"anyOf":[{"required":["contentHtml"]},{"required":["rawHtml"]}]}}}},"responses":{"201":{"description":"Sikeres válasz","content":{"application/json":{"schema":{"type":"object","properties":{"post":{"type":"object","properties":{"id":{"type":"string","description":"A létrejött poszt azonosítója."},"url":{"type":["string","null"],"description":"A poszt nyilvános címe (lásd a lista `url` mezőjét)."},"slug":{"type":"string","description":"A poszt VÉGLEGES slugja - lehet más, mint amit küldtél."},"status":{"type":"string","enum":["draft","published","scheduled"],"description":"Az elmentett állapot."}},"required":["id","url","slug","status"]}},"required":["post"]}}}},"400":{"description":"invalid_request: A séma-validáció bukott, vagy hiányzik egy kötelező paraméter. A `details[]` mezőnként sorolja fel az okot.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"401":{"description":"unauthorized: Hiányzó, hibás formátumú, ismeretlen, visszavont vagy lejárt token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"403":{"description":"forbidden: A token nem rendelkezik a szükséges scope-pal, a hívó IP nincs a kulcs allowlistáján, a fiók csomagja nem tartalmaz API-hozzáférést, vagy a fiók írás-tiltott (bemutató mód).","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"422":{"description":"unprocessable: Formailag helyes kérés, amit egy üzleti szabály utasít el. A blog-végpontokon: a megadott `websiteId` nem a fiók weboldala, vagy a fióknak még egyetlen weboldala sincs.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"429":{"description":"rate_limited: A percalapú sebességkorlát (alapból 120 kérés/perc/kulcs) túllépve.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"500":{"description":"internal_error: Váratlan szerverhiba. Egyetlen végponton (`POST /contacts`) ugyanez a hiba a rövidebb `internal` kóddal érkezik - kezeld a kettőt azonosan.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}}}},"get":{"operationId":"content.list","tags":["content"],"summary":"Blogposztok listázása","description":"A fiók blogposztjainak lapozott listája minden állapotból, a legfrissebbel kezdve. A szűrők ÉS-kapcsolatban működnek, a `total` a szűrt találatok teljes száma. A HTML törzset a lista nem tartalmazza, ahhoz a `GET /content/posts/{id}` kell.\n\nSzükséges scope: `content.readonly`.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","enum":["draft","published","scheduled"],"description":"Csak az ilyen állapotú posztok. A `published` nem adja vissza a már megjelent, `scheduled` állapotú posztokat."},"required":false,"description":"Csak az ilyen állapotú posztok. A `published` nem adja vissza a már megjelent, `scheduled` állapotú posztokat.","name":"status","in":"query"},{"schema":{"type":"string","description":"Kategória neve vagy slugja (azonosító nem). Nem létező kategóriára üres lista."},"required":false,"description":"Kategória neve vagy slugja (azonosító nem). Nem létező kategóriára üres lista.","name":"category","in":"query"},{"schema":{"type":"string","description":"Egyetlen címke, betű szerint pontos egyezéssel (a kis- és nagybetű számít)."},"required":false,"description":"Egyetlen címke, betű szerint pontos egyezéssel (a kis- és nagybetű számít).","name":"tag","in":"query"},{"schema":{"type":"string","description":"Részlet-keresés a CÍMBEN, kis- és nagybetű-függetlenül. A törzsben nem keres, a `%` és `_` szó szerinti karakter."},"required":false,"description":"Részlet-keresés a CÍMBEN, kis- és nagybetű-függetlenül. A törzsben nem keres, a `%` és `_` szó szerinti karakter.","name":"search","in":"query"},{"schema":{"type":"string","description":"Csak ennek a weboldalnak a posztjai. A fiókhoz nem tartozó azonosítóra `422 unprocessable` a válasz, nem üres lista. Elhagyva a fiók összes weboldala."},"required":false,"description":"Csak ennek a weboldalnak a posztjai. A fiókhoz nem tartozó azonosítóra `422 unprocessable` a válasz, nem üres lista. Elhagyva a fiók összes weboldala.","name":"websiteId","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":200,"default":50,"description":"Találatok maximális száma (1-200, alapértelmezés 50; a tartományon kívüli érték a határra szorítódik, nem hibát ad)"},"required":false,"description":"Találatok maximális száma (1-200, alapértelmezés 50; a tartományon kívüli érték a határra szorítódik, nem hibát ad)","name":"limit","in":"query"},{"schema":{"type":"integer","minimum":0,"maximum":1000000,"default":0,"description":"Hány találatot ugorjon át (a tartományon kívüli érték a határra szorítódik, nem hibát ad)"},"required":false,"description":"Hány találatot ugorjon át (a tartományon kívüli érték a határra szorítódik, nem hibát ad)","name":"offset","in":"query"}],"responses":{"200":{"description":"Sikeres válasz","content":{"application/json":{"schema":{"type":"object","properties":{"posts":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"A poszt állandó azonosítója. Ezt add át a `GET /content/posts/{id}` végpontnak."},"title":{"type":"string","description":"A poszt címe, a szélső szóközök levágva. Sosem üres."},"slug":{"type":"string","description":"A poszt végleges URL-részlete. Nem feltétlenül az, amit küldtél: ékezet nélkülire alakul, és ütközéskor `-2`, `-3` toldalékot kap."},"status":{"type":"string","enum":["draft","published","scheduled"],"description":"A poszt állapota. NEM azonos a nyilvános láthatósággal: a `published` azonnal élő, a `publishedAt` értékétől függetlenül; a `scheduled` a `scheduledFor` időpont elmúltával válik élővé, de az állapota VÉGLEG `scheduled` marad. Élő tehát az, ami `published`, vagy `scheduled` múltbeli `scheduledFor` értékkel."},"excerpt":{"type":["string","null"],"description":"Rövid bevezető. `null`, ha nincs."},"coverImageUrl":{"type":["string","null"],"description":"A borítókép címe: sikeres átmásolás után a fiók saját tárhelyén lévő, hosszú lejáratú cím, különben a beküldött eredeti. `null`, ha nincs borítókép."},"authorName":{"type":["string","null"],"description":"A szerző neve szabad szövegként. Nem hivatkozás a `GET /content/authors` listájára."},"tags":{"type":"array","items":{"type":"string"},"description":"A poszt címkéi, beküldési sorrendben. Címke nélkül üres tömb."},"category":{"type":["object","null"],"properties":{"id":{"type":"string","description":"A kategória azonosítója. Szűrni nem ezzel lehet: a lista `category` paramétere nevet vagy slugot vár."},"name":{"type":"string","description":"A kategória megjelenített neve."},"slug":{"type":"string","description":"A kategória URL-barát azonosítója a weboldalon belül."}},"required":["id","name","slug"],"description":"A poszt kategóriája. `null`, ha nincs, vagy ha a kategóriát azóta törölték (a poszt ilyenkor megmarad)."},"publishedAt":{"type":["string","null"],"format":"date-time","description":"A megjelenés dátuma UTC-ben - megjelenített metaadat, nem kapcsoló. `null`, amíg nincs beállítva."},"scheduledFor":{"type":["string","null"],"format":"date-time","description":"Az ütemezett megjelenés időpontja UTC-ben. `null`, ha nincs ütemezve."},"url":{"type":["string","null"],"description":"A poszt nyilvános címe: saját domainnél `https://<domain>/blog/<slug>`, különben a Dynex platform-címe. A gyakorlatban mindig kitöltött. A cím a nem élő posztnál is kiszámolódik, és a platform-cím mindig az ELSŐDLEGES weboldal blogját szolgálja ki - egy saját domain nélküli másodlagos weboldal posztjánál tehát `404`-et adhat."},"createdAt":{"type":"string","format":"date-time","description":"A létrejövés időpontja UTC-ben. A lista ez szerint rendez, csökkenően."},"updatedAt":{"type":"string","format":"date-time","description":"Az utolsó módosítás időpontja UTC-ben."}},"required":["id","title","slug","status","excerpt","coverImageUrl","authorName","tags","category","publishedAt","scheduledFor","url","createdAt","updatedAt"]},"description":"Az aktuális lap posztjai, a HTML törzs nélkül."},"total":{"type":"integer","description":"A szűrőkre illeszkedő összes poszt száma, a lapozástól függetlenül."},"limit":{"type":"integer","description":"A ténylegesen alkalmazott lapméret."},"offset":{"type":"integer","description":"Az alkalmazott eltolás. A következő laphoz add hozzá a `limit` értékét."}},"required":["posts","total","limit","offset"]}}}},"400":{"description":"invalid_request: A séma-validáció bukott, vagy hiányzik egy kötelező paraméter. A `details[]` mezőnként sorolja fel az okot.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"401":{"description":"unauthorized: Hiányzó, hibás formátumú, ismeretlen, visszavont vagy lejárt token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"403":{"description":"forbidden: A token nem rendelkezik a szükséges scope-pal, a hívó IP nincs a kulcs allowlistáján, a fiók csomagja nem tartalmaz API-hozzáférést, vagy a fiók írás-tiltott (bemutató mód).","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"422":{"description":"unprocessable: Formailag helyes kérés, amit egy üzleti szabály utasít el. A blog-végpontokon: a megadott `websiteId` nem a fiók weboldala, vagy a fióknak még egyetlen weboldala sincs.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"429":{"description":"rate_limited: A percalapú sebességkorlát (alapból 120 kérés/perc/kulcs) túllépve.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"500":{"description":"internal_error: Váratlan szerverhiba. Egyetlen végponton (`POST /contacts`) ugyanez a hiba a rövidebb `internal` kóddal érkezik - kezeld a kettőt azonosan.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}}}}},"/content/posts/{id}":{"get":{"operationId":"content.get","tags":["content"],"summary":"Egy blogposzt lekérdezése teljes tartalommal","description":"Egyetlen poszt teljes alakja: a lista mezőin felül a HTML törzs, a SEO-adatok, az olvasási idő és a `websiteId`. Más fiók posztjára ugyanúgy `404` a válasz, mint nem létezőre.\n\nSzükséges scope: `content.readonly`.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Erőforrás-azonosító"},"required":true,"description":"Erőforrás-azonosító","name":"id","in":"path"}],"responses":{"200":{"description":"Sikeres válasz","content":{"application/json":{"schema":{"type":"object","properties":{"post":{"type":"object","properties":{"id":{"type":"string","description":"A poszt állandó azonosítója. Ezt add át a `GET /content/posts/{id}` végpontnak."},"title":{"type":"string","description":"A poszt címe, a szélső szóközök levágva. Sosem üres."},"slug":{"type":"string","description":"A poszt végleges URL-részlete. Nem feltétlenül az, amit küldtél: ékezet nélkülire alakul, és ütközéskor `-2`, `-3` toldalékot kap."},"status":{"type":"string","enum":["draft","published","scheduled"],"description":"A poszt állapota. NEM azonos a nyilvános láthatósággal: a `published` azonnal élő, a `publishedAt` értékétől függetlenül; a `scheduled` a `scheduledFor` időpont elmúltával válik élővé, de az állapota VÉGLEG `scheduled` marad. Élő tehát az, ami `published`, vagy `scheduled` múltbeli `scheduledFor` értékkel."},"excerpt":{"type":["string","null"],"description":"Rövid bevezető. `null`, ha nincs."},"coverImageUrl":{"type":["string","null"],"description":"A borítókép címe: sikeres átmásolás után a fiók saját tárhelyén lévő, hosszú lejáratú cím, különben a beküldött eredeti. `null`, ha nincs borítókép."},"authorName":{"type":["string","null"],"description":"A szerző neve szabad szövegként. Nem hivatkozás a `GET /content/authors` listájára."},"tags":{"type":"array","items":{"type":"string"},"description":"A poszt címkéi, beküldési sorrendben. Címke nélkül üres tömb."},"category":{"type":["object","null"],"properties":{"id":{"type":"string","description":"A kategória azonosítója. Szűrni nem ezzel lehet: a lista `category` paramétere nevet vagy slugot vár."},"name":{"type":"string","description":"A kategória megjelenített neve."},"slug":{"type":"string","description":"A kategória URL-barát azonosítója a weboldalon belül."}},"required":["id","name","slug"],"description":"A poszt kategóriája. `null`, ha nincs, vagy ha a kategóriát azóta törölték (a poszt ilyenkor megmarad)."},"publishedAt":{"type":["string","null"],"format":"date-time","description":"A megjelenés dátuma UTC-ben - megjelenített metaadat, nem kapcsoló. `null`, amíg nincs beállítva."},"scheduledFor":{"type":["string","null"],"format":"date-time","description":"Az ütemezett megjelenés időpontja UTC-ben. `null`, ha nincs ütemezve."},"url":{"type":["string","null"],"description":"A poszt nyilvános címe: saját domainnél `https://<domain>/blog/<slug>`, különben a Dynex platform-címe. A gyakorlatban mindig kitöltött. A cím a nem élő posztnál is kiszámolódik, és a platform-cím mindig az ELSŐDLEGES weboldal blogját szolgálja ki - egy saját domain nélküli másodlagos weboldal posztjánál tehát `404`-et adhat."},"createdAt":{"type":"string","format":"date-time","description":"A létrejövés időpontja UTC-ben. A lista ez szerint rendez, csökkenően."},"updatedAt":{"type":"string","format":"date-time","description":"Az utolsó módosítás időpontja UTC-ben."},"websiteId":{"type":"string","description":"A weboldal azonosítója, amelyen a poszt megjelenik. Csak ez a végpont adja vissza, a lista nem."},"contentHtml":{"type":["string","null"],"description":"A poszt teljes HTML törzse, tisztítás és átalakítás nélkül. `null` a Dynex szerkesztőjében blokkokból összerakott posztoknál - azok tartalmát ez az API nem adja ki."},"seo":{"type":["object","null"],"additionalProperties":{},"description":"SEO-mezők szabad alakú objektumként (az API-n beküldött posztnál `title` és `description`). `null`, ha nincs."},"readingTimeMinutes":{"type":["integer","null"],"description":"Becsült olvasási idő percben (kb. 200 szó/perc, legalább 1)."}},"required":["id","title","slug","status","excerpt","coverImageUrl","authorName","tags","category","publishedAt","scheduledFor","url","createdAt","updatedAt","websiteId","contentHtml","seo","readingTimeMinutes"]}},"required":["post"]}}}},"401":{"description":"unauthorized: Hiányzó, hibás formátumú, ismeretlen, visszavont vagy lejárt token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"403":{"description":"forbidden: A token nem rendelkezik a szükséges scope-pal, a hívó IP nincs a kulcs allowlistáján, a fiók csomagja nem tartalmaz API-hozzáférést, vagy a fiók írás-tiltott (bemutató mód).","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"404":{"description":"not_found: Az erőforrás nem létezik EBBEN a fiókban. Egy másik fiókhoz tartozó azonosító is ezt adja - a kettő szándékosan megkülönböztethetetlen.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"429":{"description":"rate_limited: A percalapú sebességkorlát (alapból 120 kérés/perc/kulcs) túllépve.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}},"500":{"description":"internal_error: Váratlan szerverhiba. Egyetlen végponton (`POST /contacts`) ugyanez a hiba a rövidebb `internal` kóddal érkezik - kezeld a kettőt azonosan.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"]}},"required":["error"]}}}}}}},"/blog/authors":{"get":{"operationId":"blog.authors","tags":["blog"],"summary":"Blog-szerzők listázása","description":"A fiók újrafelhasználható blog-szerzői: név, arckép és bemutatkozás. Lapozás nincs, a végpont minden szerzőt visszaad egyszerre. A lista TÁJÉKOZTATÓ jellegű: szerzőt létrehozni ezen az API-n nem lehet, és a `POST /blog/posts` `authorName` mezője sem köti a posztot egyik itteni szerzőhöz sem - oda szabad szövegként kerül a név. Szerzőt a poszthoz kötni csak a Dynex felületén lehet. Kivezetés alatt: a v3-as utódja a `GET /api/v3/content/authors`, új integrációt arra építs.\n\nSzükséges scope: `content.readonly`. A v1 kulcson `blog.read` a neve.\n\nFelület: v1 (kivezetés alatt), a végpont a `/api/v1` előtag alatt él (lásd a művelet saját `servers` bejegyzését). Minden válasza `Deprecation: true` és `Sunset: 2027-02-03` fejlécet visel.\n\nSikeres válasz: `{ success: true, ... }` - a hasznos adat a `success` mező mellett, erőforrás-nevű kulcson.\n\nHibaválasz: `{ success: false, error: { code, message } }` - nincs `details[]` mező.","deprecated":true,"servers":[{"url":"https://prod.dynex.hu/api/v1","description":"A(z) v1 (kivezetés alatt) felület előtagja. Eddig szolgál ki: 2027-02-03."}],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Csak ennek a weboldalnak a szerzői. A fiókhoz nem tartozó azonosítóra a válasz `422 unknown_website`. Elhagyva a fiók összes weboldalának szerzője visszajön. Az érték alakját a rendszer nem vizsgálja, csak azt, hogy a fiókodhoz tartozik-e: a hibatáblában felsorolt `400 validation_error` ezért ezen a végponton a gyakorlatban nem keletkezik."},"required":false,"description":"Csak ennek a weboldalnak a szerzői. A fiókhoz nem tartozó azonosítóra a válasz `422 unknown_website`. Elhagyva a fiók összes weboldalának szerzője visszajön. Az érték alakját a rendszer nem vizsgálja, csak azt, hogy a fiókodhoz tartozik-e: a hibatáblában felsorolt `400 validation_error` ezért ezen a végponton a gyakorlatban nem keletkezik.","name":"websiteId","in":"query"}],"responses":{"200":{"description":"Sikeres válasz","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true],"description":"A v1 felület sikeres válaszainak állandó jelölője. Mindig `true`."},"authors":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"A szerző azonosítója. Az API-n sehol nem lehet átadni: sem szűrőként, sem poszt beküldésekor."},"name":{"type":"string","description":"A szerző megjelenített neve."},"avatarUrl":{"type":["string","null"],"description":"A szerző arcképének címe. `null`, ha nincs feltöltve."},"bio":{"type":["string","null"],"description":"A szerző rövid bemutatkozása. `null`, ha nincs megadva."}},"required":["id","name","avatarUrl","bio"]},"description":"A szerzők, név szerint betűrendben. Szerző nélküli fióknál üres tömb."}},"required":["success","authors"]}}}},"400":{"description":"validation_error: A törzs vagy a query megsértett egy szabályt. A v1 felületen nincs `details[]` tömb, egyszerre egy hibát kapsz. Az üzenet alakja NEM egységes: a séma-ellenőrzés `<mezőút>: <ok>` alakban nevezi meg az első hibás mezőt, a séma után futó külön ellenőrzések (például a törzs-mezők együttes feltételei vagy a lapozó-paraméterek) viszont szabad szövegű, mezőutat NEM tartalmazó angol mondatot küldenek. Az üzenetet ezért olvasásra szánjuk, gépi feldolgozásra nem - kettőspontra bontva a hibák egy részénél nem kapsz mezőnevet. Ugyanez a kód `422`-vel is érkezhet, ha a mezők külön-külön érvényesek, de együtt nem (lásd a végpontok leírását).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false],"description":"Hibás válaszban mindig false."},"error":{"type":"object","properties":{"code":{"type":"string","description":"Gépi hibakód, pl. insufficient_scope."},"message":{"type":"string","description":"Ember által olvasható ok. Validációs hibánál `<mezőút>: <ok>` alakú."}},"required":["code","message"]}},"required":["success","error"]}}}},"401":{"description":"unauthorized: Hiányzó, hibás formátumú, ismeretlen, visszavont, kikapcsolt vagy lejárt kulcs. A v1 a `dxk_` és a `dxp_` előtagú kulcsot is elfogadja, minden más előtagot azonnal elutasít. A `dxp_` tokennek lejárati ideje és ki-be kapcsolója is van, tehát egy korábban működő token ettől is elbukhat.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false],"description":"Hibás válaszban mindig false."},"error":{"type":"object","properties":{"code":{"type":"string","description":"Gépi hibakód, pl. insufficient_scope."},"message":{"type":"string","description":"Ember által olvasható ok. Validációs hibánál `<mezőút>: <ok>` alakú."}},"required":["code","message"]}},"required":["success","error"]}}}},"403":{"description":"insufficient_scope: A kulcs él, de nincs meg rajta a végponthoz kért scope. Az üzenet megnevezi, melyik hiányzik. A kulcson lévő `*` mindent megad. feature_not_available: A fiók előfizetése nem tartalmazza az API-hozzáférést (`api_access` funkció). forbidden: A hívó IP-címe nincs rajta a token allowlistáján. Csak `dxp_` tokennél fordulhat elő, és csak akkor, ha a tokenhez egyáltalán van allowlista megadva.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false],"description":"Hibás válaszban mindig false."},"error":{"type":"object","properties":{"code":{"type":"string","description":"Gépi hibakód, pl. insufficient_scope."},"message":{"type":"string","description":"Ember által olvasható ok. Validációs hibánál `<mezőút>: <ok>` alakú."}},"required":["code","message"]}},"required":["success","error"]}}}},"422":{"description":"unknown_website: A megadott `websiteId` nem a hívó fiókjának weboldala (vagy egyáltalán nem létezik).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false],"description":"Hibás válaszban mindig false."},"error":{"type":"object","properties":{"code":{"type":"string","description":"Gépi hibakód, pl. insufficient_scope."},"message":{"type":"string","description":"Ember által olvasható ok. Validációs hibánál `<mezőút>: <ok>` alakú."}},"required":["code","message"]}},"required":["success","error"]}}}},"429":{"description":"rate_limited: A kulcs túllépte a percalapú keretet (olvasás 120/perc, írás 60/perc) vagy a napi 20 000 kérést.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false],"description":"Hibás válaszban mindig false."},"error":{"type":"object","properties":{"code":{"type":"string","description":"Gépi hibakód, pl. insufficient_scope."},"message":{"type":"string","description":"Ember által olvasható ok. Validációs hibánál `<mezőút>: <ok>` alakú."}},"required":["code","message"]}},"required":["success","error"]}}}},"500":{"description":"internal_error: Váratlan szerverhiba. FIGYELEM: a v1 felületen egy váratlan adatbázis-hiba NEM az egységes hibaburokban érkezik, hanem a keretrendszer alap 500-as válaszaként - erre a törzs-formátumra tehát ne építs feldolgozást.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false],"description":"Hibás válaszban mindig false."},"error":{"type":"object","properties":{"code":{"type":"string","description":"Gépi hibakód, pl. insufficient_scope."},"message":{"type":"string","description":"Ember által olvasható ok. Validációs hibánál `<mezőút>: <ok>` alakú."}},"required":["code","message"]}},"required":["success","error"]}}}}}}},"/blog/categories":{"get":{"operationId":"blog.categories","tags":["blog"],"summary":"Blog-kategóriák listázása poszt-számmal","description":"A fiók blog-kategóriái, mindegyiknél a hozzá tartozó posztok számával. Lapozás nincs: a végpont MINDEN kategóriát visszaad egyszerre. Ez a lista a helyes forrása annak, hogy a poszt beküldésekor milyen `category` értéket küldj: az innen kapott `slug` érték garantáltan meglévő kategóriára illeszkedik, tehát nem hoz létre újat. Kategóriát létrehozni és törölni ezen az API-n nem lehet; új kategória a poszt beküldésekor, a `category` mező hatására keletkezik. Kivezetés alatt: a v3-as utódja a `GET /api/v3/content/categories`, új integrációt arra építs.\n\nSzükséges scope: `content.readonly`. A v1 kulcson `blog.read` a neve.\n\nFelület: v1 (kivezetés alatt), a végpont a `/api/v1` előtag alatt él (lásd a művelet saját `servers` bejegyzését). Minden válasza `Deprecation: true` és `Sunset: 2027-02-03` fejlécet visel.\n\nSikeres válasz: `{ success: true, ... }` - a hasznos adat a `success` mező mellett, erőforrás-nevű kulcson.\n\nHibaválasz: `{ success: false, error: { code, message } }` - nincs `details[]` mező.","deprecated":true,"servers":[{"url":"https://prod.dynex.hu/api/v1","description":"A(z) v1 (kivezetés alatt) felület előtagja. Eddig szolgál ki: 2027-02-03."}],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Csak ennek a weboldalnak a kategóriái. A fiókhoz nem tartozó azonosítóra a válasz `422 unknown_website`. Elhagyva a fiók összes weboldalának kategóriája visszajön. Az érték alakját a rendszer nem vizsgálja, csak azt, hogy a fiókodhoz tartozik-e: a hibatáblában felsorolt `400 validation_error` ezért ezen a végponton a gyakorlatban nem keletkezik."},"required":false,"description":"Csak ennek a weboldalnak a kategóriái. A fiókhoz nem tartozó azonosítóra a válasz `422 unknown_website`. Elhagyva a fiók összes weboldalának kategóriája visszajön. Az érték alakját a rendszer nem vizsgálja, csak azt, hogy a fiókodhoz tartozik-e: a hibatáblában felsorolt `400 validation_error` ezért ezen a végponton a gyakorlatban nem keletkezik.","name":"websiteId","in":"query"}],"responses":{"200":{"description":"Sikeres válasz","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true],"description":"A v1 felület sikeres válaszainak állandó jelölője. Mindig `true`."},"categories":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"A kategória azonosítója. A poszt-lista `category` szűrője ezt NEM fogadja el, oda a `slug` vagy a `name` értéket küldd."},"name":{"type":"string","description":"A kategória megjelenített neve."},"slug":{"type":"string","description":"A kategória URL-barát azonosítója a weboldalon belül. Poszt beküldésekor ezt az értéket küldd a `category` mezőben, ha meglévő kategóriába akarsz írni."},"description":{"type":["string","null"],"description":"A kategória leírása. Az API-n keletkezett kategóriáknál mindig `null` - leírást csak a Dynex felületén lehet megadni."},"postCount":{"type":"integer","description":"Hány poszt tartozik a kategóriához, MINDEN állapotot beleértve (piszkozat és ütemezett is). Üres kategóriánál `0`."}},"required":["id","name","slug","description","postCount"]},"description":"A kategóriák, név szerint betűrendben. Kategória nélküli fióknál üres tömb."}},"required":["success","categories"]}}}},"400":{"description":"validation_error: A törzs vagy a query megsértett egy szabályt. A v1 felületen nincs `details[]` tömb, egyszerre egy hibát kapsz. Az üzenet alakja NEM egységes: a séma-ellenőrzés `<mezőút>: <ok>` alakban nevezi meg az első hibás mezőt, a séma után futó külön ellenőrzések (például a törzs-mezők együttes feltételei vagy a lapozó-paraméterek) viszont szabad szövegű, mezőutat NEM tartalmazó angol mondatot küldenek. Az üzenetet ezért olvasásra szánjuk, gépi feldolgozásra nem - kettőspontra bontva a hibák egy részénél nem kapsz mezőnevet. Ugyanez a kód `422`-vel is érkezhet, ha a mezők külön-külön érvényesek, de együtt nem (lásd a végpontok leírását).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false],"description":"Hibás válaszban mindig false."},"error":{"type":"object","properties":{"code":{"type":"string","description":"Gépi hibakód, pl. insufficient_scope."},"message":{"type":"string","description":"Ember által olvasható ok. Validációs hibánál `<mezőút>: <ok>` alakú."}},"required":["code","message"]}},"required":["success","error"]}}}},"401":{"description":"unauthorized: Hiányzó, hibás formátumú, ismeretlen, visszavont, kikapcsolt vagy lejárt kulcs. A v1 a `dxk_` és a `dxp_` előtagú kulcsot is elfogadja, minden más előtagot azonnal elutasít. A `dxp_` tokennek lejárati ideje és ki-be kapcsolója is van, tehát egy korábban működő token ettől is elbukhat.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false],"description":"Hibás válaszban mindig false."},"error":{"type":"object","properties":{"code":{"type":"string","description":"Gépi hibakód, pl. insufficient_scope."},"message":{"type":"string","description":"Ember által olvasható ok. Validációs hibánál `<mezőút>: <ok>` alakú."}},"required":["code","message"]}},"required":["success","error"]}}}},"403":{"description":"insufficient_scope: A kulcs él, de nincs meg rajta a végponthoz kért scope. Az üzenet megnevezi, melyik hiányzik. A kulcson lévő `*` mindent megad. feature_not_available: A fiók előfizetése nem tartalmazza az API-hozzáférést (`api_access` funkció). forbidden: A hívó IP-címe nincs rajta a token allowlistáján. Csak `dxp_` tokennél fordulhat elő, és csak akkor, ha a tokenhez egyáltalán van allowlista megadva.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false],"description":"Hibás válaszban mindig false."},"error":{"type":"object","properties":{"code":{"type":"string","description":"Gépi hibakód, pl. insufficient_scope."},"message":{"type":"string","description":"Ember által olvasható ok. Validációs hibánál `<mezőút>: <ok>` alakú."}},"required":["code","message"]}},"required":["success","error"]}}}},"422":{"description":"unknown_website: A megadott `websiteId` nem a hívó fiókjának weboldala (vagy egyáltalán nem létezik).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false],"description":"Hibás válaszban mindig false."},"error":{"type":"object","properties":{"code":{"type":"string","description":"Gépi hibakód, pl. insufficient_scope."},"message":{"type":"string","description":"Ember által olvasható ok. Validációs hibánál `<mezőút>: <ok>` alakú."}},"required":["code","message"]}},"required":["success","error"]}}}},"429":{"description":"rate_limited: A kulcs túllépte a percalapú keretet (olvasás 120/perc, írás 60/perc) vagy a napi 20 000 kérést.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false],"description":"Hibás válaszban mindig false."},"error":{"type":"object","properties":{"code":{"type":"string","description":"Gépi hibakód, pl. insufficient_scope."},"message":{"type":"string","description":"Ember által olvasható ok. Validációs hibánál `<mezőút>: <ok>` alakú."}},"required":["code","message"]}},"required":["success","error"]}}}},"500":{"description":"internal_error: Váratlan szerverhiba. FIGYELEM: a v1 felületen egy váratlan adatbázis-hiba NEM az egységes hibaburokban érkezik, hanem a keretrendszer alap 500-as válaszaként - erre a törzs-formátumra tehát ne építs feldolgozást.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false],"description":"Hibás válaszban mindig false."},"error":{"type":"object","properties":{"code":{"type":"string","description":"Gépi hibakód, pl. insufficient_scope."},"message":{"type":"string","description":"Ember által olvasható ok. Validációs hibánál `<mezőút>: <ok>` alakú."}},"required":["code","message"]}},"required":["success","error"]}}}}}}},"/blog/posts":{"post":{"operationId":"blog.create","tags":["blog"],"summary":"Blogposzt létrehozása","description":"Új blogposztot hoz létre a fiók egyik weboldalán. A mentés azonnali, jóváhagyási lépés nincs. Kötelező a `title`, és a `contentHtml` vagy a `rawHtml` mezőben a HTML törzs; minden más elhagyható. A válasz a poszt azonosítóját, a VÉGLEGES slugját, a nyilvános címét és az állapotát adja vissza - a poszt teljes alakját ezután a `GET /blog/posts/{id}` végponttal olvashatod vissza. FIGYELEM: ez az EGYETLEN író blog-végpont. Módosítani és törölni az API-n nem lehet, tehát egy elgépelt címet vagy rossz weboldalra küldött posztot csak a Dynex felületén lehet helyrehozni. Kivezetés alatt: a v3-as utódja a `POST /api/v3/content/posts`, új integrációt arra építs.\n\nSzükséges scope: `content.write`. A v1 kulcson `blog.write` a neve.\n\nFelület: v1 (kivezetés alatt), a végpont a `/api/v1` előtag alatt él (lásd a művelet saját `servers` bejegyzését). Minden válasza `Deprecation: true` és `Sunset: 2027-02-03` fejlécet visel.\n\nSikeres válasz: `{ success: true, ... }` - a hasznos adat a `success` mező mellett, erőforrás-nevű kulcson.\n\nHibaválasz: `{ success: false, error: { code, message } }` - nincs `details[]` mező.\n\nA `contentHtml` és `rawHtml` mező közül legalább egyet el kell küldeni. Külön-külön mindegyik elhagyható - a „vagy\" kapcsolatot a séma nem tudja kifejezni -, de ha egyiket sem küldöd, a válasz 400.","deprecated":true,"servers":[{"url":"https://prod.dynex.hu/api/v1","description":"A(z) v1 (kivezetés alatt) felület előtagja. Eddig szolgál ki: 2027-02-03."}],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string","minLength":1,"description":"A poszt címe. AZ EGYETLEN feltétel nélkül kötelező mező. A szélső szóközök levágódnak, a csak szóközből álló cím üresnek számít és `400`-at ad. Hosszkorlát nincs. Slug hiányában ebből képződik a poszt URL-je."},"contentHtml":{"type":"string","description":"A poszt HTML törzse. A `rawHtml`-lel EGYÜTT alkot egy kötelező párt: a kettő közül legalább az egyiknek nem üres HTML-t kell tartalmaznia, különben a válasz `400`. A rendszer a HTML-t nem tisztítja és nem alakítja át, csak a szélső szóközöket vágja le, és ebből számolja az olvasási időt is. FIGYELEM a sorrendre: ha ezt a mezőt ELKÜLDÖD üres stringgel, a rendszer NEM esik vissza a `rawHtml`-re - az üres érték jelen lévő értéknek számít, és a kérés `400`-at ad, hiába küldtél mellé `rawHtml`-t. Ha a törzset a másik mezőben küldöd, ezt a kulcsot hagyd ki teljesen."},"rawHtml":{"type":"string","description":"A `contentHtml` másik neve, a korábbi rendszerből átvett integrációk kedvéért. Csak akkor veszi figyelembe a rendszer, ha a `contentHtml` kulcs egyáltalán nincs a törzsben. A kettőt együtt küldeni felesleges: ilyenkor a `contentHtml` nyer, a `rawHtml` tartalma nyomtalanul elveszik."},"description":{"type":"string","description":"A rövid bevezető másik neve. Csak akkor kerül a poszt `excerpt` mezőjébe, ha az `excerpt` kulcs nincs a törzsben. Külön mezőként nem tárolódik, a válaszban és a lekérdezésekben `excerpt` néven jön vissza."},"excerpt":{"type":"string","description":"Rövid bevezető a listaoldalakhoz és a megosztás-előnézetekhez. Elsőbbsége van a `description` mezővel szemben. Hosszkorlát nincs, és a rendszer nem vágja le: ha rövid felvezetőt akarsz, magad rövidítsd. Elhagyva a poszt `excerpt` mezője `null` marad - a rendszer NEM generál bevezetőt a törzsből."},"coverImageUrl":{"type":"string","format":"uri","description":"A borítókép nyilvános címe. Kötelezően `https://` kezdetű (a `http://` `400`-at ad, mert a nyilvános blogon kevert tartalmat okozna). FIGYELEM a sorrendre: az előtagot a rendszer a TÖRZS-ellenőrzés UTÁN vizsgálja, tehát ha a `contentHtml`/`rawHtml` pár is hibás, előbb arról kapsz `400`-at, és a borítókép hibája csak a javítás után derül ki - egy körben mindig csak EGY hibaüzenetet kapsz. A rendszer megpróbálja a képet a saját tárhelyére átmásolni, és siker esetén az ottani, hosszú lejáratú címet tárolja - lásd a korlátokat lent. Ha a másolás bármiért nem megy, a beküldött URL marad, változtatás nélkül: a poszt ilyenkor egy IDEGEN kiszolgálóra mutató képet hordoz, aminek az elérhetőségéért nem tudunk felelni."},"slug":{"type":"string","description":"A kívánt URL-részlet. Nem szó szerint kerül be: a rendszer ugyanúgy átalakítja, mint a címet (kisbetűsítés, ékezet-eltávolítás, minden más karakter kötőjelre cserélése, a szélső kötőjelek levágása), tehát az `Őszi Menü!` értékből `oszi-menu` lesz. Ha az eredmény üres string (például csak írásjeleket küldtél), a `bejegyzes` szó lép a helyére. Elhagyva a `title` mezőből képződik. A weboldalon belüli egyediséget a rendszer biztosítja, szükség esetén `-2`, `-3` toldalékkal, ezért a VÉGLEGES slugot mindig a válaszból olvasd ki."},"tags":{"type":"array","items":{"type":"string"},"description":"A poszt címkéi. Szabad szöveg, nincs előzetes regisztráció és nincs darabszám-korlát. Ha a tömb BÁRMELYIK eleme nem string, a teljes kérés `400`-at kap. Elhagyva a poszt üres címkelistát kap. A címkékre a lista-végpont `tag` szűrője keres, betű szerint pontos egyezéssel, ezért érdemes egységes, ékezet és nagybetű nélküli alakot használni."},"category":{"type":"string","minLength":1,"description":"A kategória NEVE vagy SLUGJA a cél-weboldalon. A rendszer végignézi a weboldal kategóriáit, és az ELSŐ olyan sort veszi, amelyik VAGY slug szerint, VAGY név szerint illeszkedik - a két feltétel egyenrangú, és a sorok bejárási sorrendje nem garantált, tehát ha két kategóriára is illene az érték, nem jósolható meg, melyiket kapod. HA EGYIK SEM ILLESZKEDIK, LÉTREHOZZA - nem hibázik. Egy elgépelt név tehát új, egyelemű kategóriát csinál, ami a nyilvános blog kategória-menüjében is megjelenik. A szélső szóközök levágódnak, a csak szóközből álló érték `400`-at ad. Elhagyva a poszt kategória nélkül jön létre. A két ág pontos tűréshatárát lásd a korlátoknál."},"authorName":{"type":"string","description":"A szerző neve szabad szövegként. FIGYELEM: ez NEM köti a posztot a fiók szerző-készletéhez (`GET /blog/authors`) - az API-n létrehozott poszt szerző-azonosítója mindig üresen marad, akkor is, ha a beküldött név pontosan egyezik egy meglévő szerzővel. Ennek következménye, hogy a szerző arcképe és bemutatkozása nem jelenik meg a poszt alatt. Szerzőhöz kötni a posztot csak a Dynex felületén lehet."},"status":{"type":"string","enum":["draft","published","scheduled"],"description":"A poszt kezdő állapota, alapértelmezés `draft`. A `published` AZONNAL nyilvánossá teszi a posztot, a `publishedAt` értékétől függetlenül. A `scheduled` esetén a `scheduledFor` mező KÖTELEZŐ, hiánya `422`-t ad; a poszt ilyenkor a megadott időpont elteltével válik magától olvashatóvá, az állapota viszont `scheduled` marad. A `draft` sosem nyilvános. Utólagos állapotváltásra ezen az API-n nincs végpont."},"publishedAt":{"type":"string","description":"A megjelenés dátuma. Megjelenített metaadat, NEM kapcsoló: a jövőbe tett érték nem késlelteti a `published` poszt kikerülését, a múltba tett pedig nem tesz élővé egy piszkozatot. Elhagyva a `published` státuszú poszt a létrehozás pillanatát kapja, a `draft` és a `scheduled` pedig `null`-t. A formátum-ellenőrzés megengedő: minden olyan szöveget elfogad, amit a rendszer értelmezni tud dátumként (például a puszta `2026-09-20` is jó, ilyenkor éjfélt jelent), de a félreértések elkerülésére küldj teljes, UTC-s ISO-8601 időbélyeget."},"scheduledFor":{"type":"string","description":"Az ütemezett megjelenés időpontja. Csak a `scheduled` státusszal együtt van értelme, ott viszont kötelező. A rendszer NEM ellenőrzi, hogy a jövőben van-e: egy múltbeli időpont azonnal élővé teszi a posztot. Ugyanaz a megengedő formátum-ellenőrzés vonatkozik rá, mint a `publishedAt` mezőre."},"websiteId":{"type":"string","description":"Melyik weboldalra kerüljön a poszt. Az azonosítót a `GET /blog/posts/{id}` válaszának `websiteId` mezőjéből vagy a Dynex felületéről szerzed meg - a LISTA (`GET /blog/posts`) szándékosan NEM adja vissza a weboldal azonosítóját, ott hiába keresed. A fiókhoz nem tartozó azonosítóra `422 unknown_website` a válasz. Elhagyva a rendszer maga választ: az elsődleges weboldalt, ha nincs ilyen, akkor a LEGRÉGEBBEN létrehozottat - ez nem feltétlenül az, amelyiken a legutóbb dolgoztál. Ha a fióknak egyetlen weboldala sincs, a válasz `422 no_website`."},"seo":{"type":"object","properties":{"title":{"type":"string","description":"A keresőkben és a megosztás-előnézetben mutatott cím. Elhagyva a poszt címe használódik."},"description":{"type":"string","description":"A keresőkben mutatott rövid leírás."}},"description":"SEO-mezők. A `title` és a `description` kulcson kívül minden más kulcs CSENDBEN kimarad a mentésből, hibaüzenet nélkül. Elhagyva a poszt SEO-adata `null` marad."}},"required":["title"],"anyOf":[{"required":["contentHtml"]},{"required":["rawHtml"]}]}}}},"responses":{"201":{"description":"Sikeres válasz","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true],"description":"A v1 felület sikeres válaszainak állandó jelölője. Mindig `true`."},"post":{"type":"object","properties":{"id":{"type":"string","description":"A létrejött poszt azonosítója. Ezzel kérdezhető vissza a teljes alak a `GET /blog/posts/{id}` végponton."},"url":{"type":["string","null"],"description":"A poszt nyilvános címe. A gyakorlatban mindig kitöltött: `null` csak akkor keletkezne, ha a weboldalhoz nincs saját domain bekötve ÉS a fiók slugja is üres, ilyen fiók viszont nem jön létre - a `null` a címszámoló függvény szignatúráját tükrözi, nem egy valós üzleti állapotot. A cím megléte NEM jelenti azt, hogy a lap be is tölt: a `draft` és a még nem esedékes `scheduled` poszt címe is kiszámolódik, és egy másodlagos, saját domain nélküli weboldalra küldött poszt platform-címe (`/s/<fiók-slug>/...`) akkor is `404`-et ad, ha a poszt élő - az az útvonal mindig az ELSŐDLEGES weboldal blogját szolgálja ki."},"slug":{"type":"string","description":"A poszt VÉGLEGES slugja, a beküldött érték átalakítása és az egyediség biztosítása után. Ez lehet más, mint amit küldtél."},"status":{"type":"string","enum":["draft","published","scheduled"],"description":"A poszt állapota, ahogyan elmentettük: a beküldött `status`, vagy `draft`, ha nem küldtél ilyet."}},"required":["id","url","slug","status"]}},"required":["success","post"]}}}},"400":{"description":"invalid_json: A kérés törzse nem értelmezhető JSON-ként (elgépelt vessző, lecsonkolt törzs, nem JSON tartalom). validation_error: A törzs vagy a query megsértett egy szabályt. A v1 felületen nincs `details[]` tömb, egyszerre egy hibát kapsz. Az üzenet alakja NEM egységes: a séma-ellenőrzés `<mezőút>: <ok>` alakban nevezi meg az első hibás mezőt, a séma után futó külön ellenőrzések (például a törzs-mezők együttes feltételei vagy a lapozó-paraméterek) viszont szabad szövegű, mezőutat NEM tartalmazó angol mondatot küldenek. Az üzenetet ezért olvasásra szánjuk, gépi feldolgozásra nem - kettőspontra bontva a hibák egy részénél nem kapsz mezőnevet. Ugyanez a kód `422`-vel is érkezhet, ha a mezők külön-külön érvényesek, de együtt nem (lásd a végpontok leírását).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false],"description":"Hibás válaszban mindig false."},"error":{"type":"object","properties":{"code":{"type":"string","description":"Gépi hibakód, pl. insufficient_scope."},"message":{"type":"string","description":"Ember által olvasható ok. Validációs hibánál `<mezőút>: <ok>` alakú."}},"required":["code","message"]}},"required":["success","error"]}}}},"401":{"description":"unauthorized: Hiányzó, hibás formátumú, ismeretlen, visszavont, kikapcsolt vagy lejárt kulcs. A v1 a `dxk_` és a `dxp_` előtagú kulcsot is elfogadja, minden más előtagot azonnal elutasít. A `dxp_` tokennek lejárati ideje és ki-be kapcsolója is van, tehát egy korábban működő token ettől is elbukhat.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false],"description":"Hibás válaszban mindig false."},"error":{"type":"object","properties":{"code":{"type":"string","description":"Gépi hibakód, pl. insufficient_scope."},"message":{"type":"string","description":"Ember által olvasható ok. Validációs hibánál `<mezőút>: <ok>` alakú."}},"required":["code","message"]}},"required":["success","error"]}}}},"403":{"description":"insufficient_scope: A kulcs él, de nincs meg rajta a végponthoz kért scope. Az üzenet megnevezi, melyik hiányzik. A kulcson lévő `*` mindent megad. feature_not_available: A fiók előfizetése nem tartalmazza az API-hozzáférést (`api_access` funkció). forbidden: A hívó IP-címe nincs rajta a token allowlistáján. Csak `dxp_` tokennél fordulhat elő, és csak akkor, ha a tokenhez egyáltalán van allowlista megadva. account_read_only: A fiók írás-tiltott (bemutató mód vagy zárolás). Csak író metódusnál jelentkezik, az olvasás ilyenkor is működik.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false],"description":"Hibás válaszban mindig false."},"error":{"type":"object","properties":{"code":{"type":"string","description":"Gépi hibakód, pl. insufficient_scope."},"message":{"type":"string","description":"Ember által olvasható ok. Validációs hibánál `<mezőút>: <ok>` alakú."}},"required":["code","message"]}},"required":["success","error"]}}}},"422":{"description":"unknown_website: A megadott `websiteId` nem a hívó fiókjának weboldala (vagy egyáltalán nem létezik). no_website: A fióknak még egyetlen weboldala sincs, márpedig blogposzt csak weboldalon jelenhet meg.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false],"description":"Hibás válaszban mindig false."},"error":{"type":"object","properties":{"code":{"type":"string","description":"Gépi hibakód, pl. insufficient_scope."},"message":{"type":"string","description":"Ember által olvasható ok. Validációs hibánál `<mezőút>: <ok>` alakú."}},"required":["code","message"]}},"required":["success","error"]}}}},"429":{"description":"rate_limited: A kulcs túllépte a percalapú keretet (olvasás 120/perc, írás 60/perc) vagy a napi 20 000 kérést.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false],"description":"Hibás válaszban mindig false."},"error":{"type":"object","properties":{"code":{"type":"string","description":"Gépi hibakód, pl. insufficient_scope."},"message":{"type":"string","description":"Ember által olvasható ok. Validációs hibánál `<mezőút>: <ok>` alakú."}},"required":["code","message"]}},"required":["success","error"]}}}},"500":{"description":"internal_error: Váratlan szerverhiba. FIGYELEM: a v1 felületen egy váratlan adatbázis-hiba NEM az egységes hibaburokban érkezik, hanem a keretrendszer alap 500-as válaszaként - erre a törzs-formátumra tehát ne építs feldolgozást.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false],"description":"Hibás válaszban mindig false."},"error":{"type":"object","properties":{"code":{"type":"string","description":"Gépi hibakód, pl. insufficient_scope."},"message":{"type":"string","description":"Ember által olvasható ok. Validációs hibánál `<mezőút>: <ok>` alakú."}},"required":["code","message"]}},"required":["success","error"]}}}}}},"get":{"operationId":"blog.list","tags":["blog"],"summary":"Blogposztok listázása","description":"A fiók blogposztjainak lapozott listája, minden állapotból (a piszkozatokat is beleértve), a legfrissebbel kezdve. A szűrők ÉS-kapcsolatban működnek. A válasz a `total` mezőben a SZŰRT találatok teljes számát adja meg, tehát a lapok száma ebből számolható. A posztok HTML törzsét ez a végpont MÉRETOKOKBÓL nem adja vissza: ahhoz hívd a `GET /blog/posts/{id}` végpontot. Kivezetés alatt: a v3-as utódja a `GET /api/v3/content/posts`, új integrációt arra építs.\n\nSzükséges scope: `content.readonly`. A v1 kulcson `blog.read` a neve.\n\nFelület: v1 (kivezetés alatt), a végpont a `/api/v1` előtag alatt él (lásd a művelet saját `servers` bejegyzését). Minden válasza `Deprecation: true` és `Sunset: 2027-02-03` fejlécet visel.\n\nSikeres válasz: `{ success: true, ... }` - a hasznos adat a `success` mező mellett, erőforrás-nevű kulcson.\n\nHibaválasz: `{ success: false, error: { code, message } }` - nincs `details[]` mező.","deprecated":true,"servers":[{"url":"https://prod.dynex.hu/api/v1","description":"A(z) v1 (kivezetés alatt) felület előtagja. Eddig szolgál ki: 2027-02-03."}],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Hány poszt jöjjön vissza egy lapon. Alapértelmezés `20`, felső határ `100` - a nagyobb érték nem hibázik, csendben 100-ra szorul. A `0` érvényes, és üres listát ad a valós `total` mellett. Nem nem-negatív egész értékre (tizedes, negatív, szöveg) a válasz `400 validation_error`."},"required":false,"description":"Hány poszt jöjjön vissza egy lapon. Alapértelmezés `20`, felső határ `100` - a nagyobb érték nem hibázik, csendben 100-ra szorul. A `0` érvényes, és üres listát ad a valós `total` mellett. Nem nem-negatív egész értékre (tizedes, negatív, szöveg) a válasz `400 validation_error`.","name":"limit","in":"query"},{"schema":{"type":"string","description":"Hány posztot ugorjon át a lista elejéről. Alapértelmezés `0`. Felső korlátja nincs: a találatok számán túli eltolás üres listát ad a valós `total` mellett, nem hibát. Nem nem-negatív egész értékre a válasz `400 validation_error`."},"required":false,"description":"Hány posztot ugorjon át a lista elejéről. Alapértelmezés `0`. Felső korlátja nincs: a találatok számán túli eltolás üres listát ad a valós `total` mellett, nem hibát. Nem nem-negatív egész értékre a válasz `400 validation_error`.","name":"offset","in":"query"},{"schema":{"type":"string","enum":["draft","published","scheduled"],"description":"Csak az ilyen állapotú posztok. A három érték valamelyike, különben `400 validation_error` - a szélső szóközök itt sem vágódnak le, tehát a `?status=%20draft` is hibát ad. FIGYELEM: a `published` szűrő NEM a nyilvánosan látható posztokat adja vissza - a már megjelent, ütemezett posztok `scheduled` állapotúak maradnak. Az élő posztok teljes körének lekérdezéséhez a `published` találatokhoz vedd hozzá a múltbeli `scheduledFor` értékű `scheduled` posztokat."},"required":false,"description":"Csak az ilyen állapotú posztok. A három érték valamelyike, különben `400 validation_error` - a szélső szóközök itt sem vágódnak le, tehát a `?status=%20draft` is hibát ad. FIGYELEM: a `published` szűrő NEM a nyilvánosan látható posztokat adja vissza - a már megjelent, ütemezett posztok `scheduled` állapotúak maradnak. Az élő posztok teljes körének lekérdezéséhez a `published` találatokhoz vedd hozzá a múltbeli `scheduledFor` értékű `scheduled` posztokat.","name":"status","in":"query"},{"schema":{"type":"string","description":"Szűrés kategóriára, NÉV vagy SLUG alapján - kategória-azonosítóval nem működik. A párosítás ugyanaz, mint a poszt beküldésénél: két egyenrangú ág, az egyik a slugosított alakot veti össze a tárolt sluggal (kisbetűsítve, ékezet nélkül, a szélső szóközöket és az írásjeleket levágva), a másik a kisbetűs nevet a tárolt névvel (a szélső szóközöket itt is levágva, de ÉKEZET-érzékenyen). Nem létező kategóriára `200` a válasz, üres listával."},"required":false,"description":"Szűrés kategóriára, NÉV vagy SLUG alapján - kategória-azonosítóval nem működik. A párosítás ugyanaz, mint a poszt beküldésénél: két egyenrangú ág, az egyik a slugosított alakot veti össze a tárolt sluggal (kisbetűsítve, ékezet nélkül, a szélső szóközöket és az írásjeleket levágva), a másik a kisbetűs nevet a tárolt névvel (a szélső szóközöket itt is levágva, de ÉKEZET-érzékenyen). Nem létező kategóriára `200` a válasz, üres listával.","name":"category","in":"query"},{"schema":{"type":"string","description":"Szűrés egyetlen címkére. Az egyezésnek BETŰ SZERINT pontosnak kell lennie: a kis- és nagybetű számít, és a szélső szóközök sem vágódnak le, ezért a `?tag=%20vegan` NEM ugyanaz, mint a `?tag=vegan`. Ez az egyetlen szűrő, ami a szóközöket így kezeli. Több címkére egyszerre nem lehet szűrni."},"required":false,"description":"Szűrés egyetlen címkére. Az egyezésnek BETŰ SZERINT pontosnak kell lennie: a kis- és nagybetű számít, és a szélső szóközök sem vágódnak le, ezért a `?tag=%20vegan` NEM ugyanaz, mint a `?tag=vegan`. Ez az egyetlen szűrő, ami a szóközöket így kezeli. Több címkére egyszerre nem lehet szűrni.","name":"tag","in":"query"},{"schema":{"type":"string","description":"Keresés a poszt CÍMÉBEN, részlet-egyezéssel, a kis- és nagybetűt figyelmen kívül hagyva. A törzsre és a bevezetőre nem keres. A szélső szóközök levágódnak, tehát a `?search=%20vegan` ugyanazt adja, mint a `?search=vegan`, egy csupa szóközből álló érték (`?search=%20`) pedig úgy viselkedik, mintha meg sem adtad volna: a válasz az összes posztot hozza. A `%` és a `_` közönséges karakterként keresődik, nem helyettesítő jelként."},"required":false,"description":"Keresés a poszt CÍMÉBEN, részlet-egyezéssel, a kis- és nagybetűt figyelmen kívül hagyva. A törzsre és a bevezetőre nem keres. A szélső szóközök levágódnak, tehát a `?search=%20vegan` ugyanazt adja, mint a `?search=vegan`, egy csupa szóközből álló érték (`?search=%20`) pedig úgy viselkedik, mintha meg sem adtad volna: a válasz az összes posztot hozza. A `%` és a `_` közönséges karakterként keresődik, nem helyettesítő jelként.","name":"search","in":"query"},{"schema":{"type":"string","description":"Csak ennek a weboldalnak a posztjai. Az azonosítót a `GET /blog/posts/{id}` válaszának `websiteId` mezőjéből vagy a Dynex felületéről kapod - EBBEN a lista-válaszban nincs benne. A fiókhoz nem tartozó azonosítóra a válasz `422 unknown_website` - nem üres lista, tehát az elgépelt azonosító azonnal kiderül. Az érték alakját a rendszer nem vizsgálja, és a szóközöket sem vágja le róla."},"required":false,"description":"Csak ennek a weboldalnak a posztjai. Az azonosítót a `GET /blog/posts/{id}` válaszának `websiteId` mezőjéből vagy a Dynex felületéről kapod - EBBEN a lista-válaszban nincs benne. A fiókhoz nem tartozó azonosítóra a válasz `422 unknown_website` - nem üres lista, tehát az elgépelt azonosító azonnal kiderül. Az érték alakját a rendszer nem vizsgálja, és a szóközöket sem vágja le róla.","name":"websiteId","in":"query"}],"responses":{"200":{"description":"Sikeres válasz","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true],"description":"A v1 felület sikeres válaszainak állandó jelölője. Mindig `true`."},"total":{"type":"integer","description":"A SZŰRŐKRE illeszkedő összes poszt száma, a lapozástól függetlenül. Ebből számolható, hány lap van hátra."},"posts":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"A poszt állandó azonosítója. Ezt add át a `GET /blog/posts/{id}` végpontnak."},"title":{"type":"string","description":"A poszt címe, a beküldött alakban (a szélső szóközök levágva). Sosem üres és sosem `null`."},"slug":{"type":"string","description":"A poszt URL-barát azonosítója a weboldalon belül. Nem feltétlenül az, amit beküldtél: ékezet nélkülire alakul, és ütközés esetén `-2`, `-3` toldalékot kap."},"status":{"type":"string","enum":["draft","published","scheduled"],"description":"A poszt állapota: `draft`, `published` vagy `scheduled`. FIGYELEM: ez NEM azonos azzal, hogy a poszt látszik-e a nyilvános blogon. A `published` azonnal élő, a `publishedAt` értékétől FÜGGETLENÜL (a jövőbe tett `publishedAt` sem késlelteti, az csak megjelenített dátum). A `scheduled` poszt akkor válik élővé, amikor a `scheduledFor` időpont elmúlt - ezt a rendszer minden kérésnél újraszámolja, ütemezett feladat nélkül, ezért az állapot az adatbázisban VÉGLEG `scheduled` marad, a poszt akkor is, amikor már hónapok óta olvasható. Ha azt akarod tudni, látszik-e a poszt, a `status` és a `scheduledFor` mezőt EGYÜTT nézd: élő az, ami `published`, vagy `scheduled` múltbeli `scheduledFor` értékkel."},"excerpt":{"type":["string","null"],"description":"Rövid bevezető a listaoldalakhoz. `null`, ha nincs. Beküldéskor az `excerpt`, ennek hiányában a `description` mező tölti fel."},"coverImageUrl":{"type":["string","null"],"description":"A borítókép URL-je. Ha a beküldött képet sikerült a fiók saját tárhelyére átmásolni, ez egy hosszú lejáratú, aláírt tárhely-URL, egyébként a beküldött eredeti cím. `null`, ha nincs borítókép."},"authorName":{"type":["string","null"],"description":"A szerző neve szabad szövegként, ahogyan beküldték. `null`, ha nincs megadva. Ez NEM hivatkozás a `GET /blog/authors` listájára: az API-n létrehozott posztnak nincs szerző-azonosítója."},"tags":{"type":"array","items":{"type":"string"},"description":"A poszt címkéi. Mindig tömb, címke nélküli posztnál üres. A sorrend a beküldött sorrend."},"category":{"type":["object","null"],"properties":{"id":{"type":"string","description":"A kategória azonosítója. Ezzel nem lehet szűrni: a lista `category` paramétere nevet vagy slugot vár, nem azonosítót."},"name":{"type":"string","description":"A kategória megjelenített neve, ahogyan a poszt beküldésekor megadták."},"slug":{"type":"string","description":"A kategória URL-barát azonosítója a weboldalon belül."}},"required":["id","name","slug"],"description":"A poszt kategóriája. `null`, ha a poszt kategória nélkül jött létre, vagy ha a kategóriáját azóta törölték: a kategória törlése a posztokról előbb leveszi a hivatkozást, a poszt maga megmarad, csak kategória nélkül. Elárvult, feloldhatatlan kategória-hivatkozást tehát nem fogsz látni."},"publishedAt":{"type":["string","null"],"format":"date-time","description":"A megjelenés dátuma UTC-ben - megjelenített metaadat, nem kapcsoló. `null`, amíg nincs beállítva. Beküldéskor a `publishedAt` értéke kerül ide; ha nem küldtél ilyet, de a státusz `published`, akkor a létrehozás pillanata."},"scheduledFor":{"type":["string","null"],"format":"date-time","description":"Az ütemezett megjelenés időpontja UTC-ben. `null`, ha nincs ütemezve. A `scheduled` státuszú poszt ettől az időponttól látszik a nyilvános blogon."},"url":{"type":["string","null"],"description":"A poszt nyilvános címe. Bekötött saját domainnél `https://<domain>/blog/<slug>`, egyébként a Dynex platform-címén `<bázis-URL>/s/<fiók-slug>/blog/<slug>`. A GYAKORLATBAN mindig kitöltött: `null` csak akkor keletkezne, ha a weboldalhoz nincs saját domain ÉS a fiók slugja is üres, ilyen fiók viszont nem jön létre - a `null` a címszámoló függvény szignatúráját tükrözi, nem egy valós üzleti állapotot. A mező azt NEM garantálja, hogy a cím be is tölt, és ennek két oka lehet. (1) A nem élő (piszkozat vagy még ütemezett) poszt címe is kiszámolódik. (2) A platform-cím (`/s/<fiók-slug>/...`) mindig az ELSŐDLEGES weboldal blogját szolgálja ki, ezért egy másodlagos, saját domain nélküli weboldalra küldött poszt címe akkor is `404`-et ad, ha a poszt egyébként élő - ott csak a weboldalhoz bekötött saját domain ad működő címet."},"createdAt":{"type":"string","format":"date-time","description":"A poszt létrejöttének időpontja UTC-ben. A lista EZ SZERINT rendez, csökkenően."},"updatedAt":{"type":"string","format":"date-time","description":"Az utolsó módosítás időpontja UTC-ben. Az API-n létrehozott posztnál a létrehozás pillanatával egyezik, és csak a Dynex felületén végzett szerkesztés mozdítja el."}},"required":["id","title","slug","status","excerpt","coverImageUrl","authorName","tags","category","publishedAt","scheduledFor","url","createdAt","updatedAt"]},"description":"Az aktuális lap posztjai, létrehozás szerint csökkenő sorrendben. A HTML törzs (`contentHtml`) szándékosan nincs benne."}},"required":["success","total","posts"]}}}},"400":{"description":"validation_error: A törzs vagy a query megsértett egy szabályt. A v1 felületen nincs `details[]` tömb, egyszerre egy hibát kapsz. Az üzenet alakja NEM egységes: a séma-ellenőrzés `<mezőút>: <ok>` alakban nevezi meg az első hibás mezőt, a séma után futó külön ellenőrzések (például a törzs-mezők együttes feltételei vagy a lapozó-paraméterek) viszont szabad szövegű, mezőutat NEM tartalmazó angol mondatot küldenek. Az üzenetet ezért olvasásra szánjuk, gépi feldolgozásra nem - kettőspontra bontva a hibák egy részénél nem kapsz mezőnevet. Ugyanez a kód `422`-vel is érkezhet, ha a mezők külön-külön érvényesek, de együtt nem (lásd a végpontok leírását).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false],"description":"Hibás válaszban mindig false."},"error":{"type":"object","properties":{"code":{"type":"string","description":"Gépi hibakód, pl. insufficient_scope."},"message":{"type":"string","description":"Ember által olvasható ok. Validációs hibánál `<mezőút>: <ok>` alakú."}},"required":["code","message"]}},"required":["success","error"]}}}},"401":{"description":"unauthorized: Hiányzó, hibás formátumú, ismeretlen, visszavont, kikapcsolt vagy lejárt kulcs. A v1 a `dxk_` és a `dxp_` előtagú kulcsot is elfogadja, minden más előtagot azonnal elutasít. A `dxp_` tokennek lejárati ideje és ki-be kapcsolója is van, tehát egy korábban működő token ettől is elbukhat.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false],"description":"Hibás válaszban mindig false."},"error":{"type":"object","properties":{"code":{"type":"string","description":"Gépi hibakód, pl. insufficient_scope."},"message":{"type":"string","description":"Ember által olvasható ok. Validációs hibánál `<mezőút>: <ok>` alakú."}},"required":["code","message"]}},"required":["success","error"]}}}},"403":{"description":"insufficient_scope: A kulcs él, de nincs meg rajta a végponthoz kért scope. Az üzenet megnevezi, melyik hiányzik. A kulcson lévő `*` mindent megad. feature_not_available: A fiók előfizetése nem tartalmazza az API-hozzáférést (`api_access` funkció). forbidden: A hívó IP-címe nincs rajta a token allowlistáján. Csak `dxp_` tokennél fordulhat elő, és csak akkor, ha a tokenhez egyáltalán van allowlista megadva.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false],"description":"Hibás válaszban mindig false."},"error":{"type":"object","properties":{"code":{"type":"string","description":"Gépi hibakód, pl. insufficient_scope."},"message":{"type":"string","description":"Ember által olvasható ok. Validációs hibánál `<mezőút>: <ok>` alakú."}},"required":["code","message"]}},"required":["success","error"]}}}},"422":{"description":"unknown_website: A megadott `websiteId` nem a hívó fiókjának weboldala (vagy egyáltalán nem létezik).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false],"description":"Hibás válaszban mindig false."},"error":{"type":"object","properties":{"code":{"type":"string","description":"Gépi hibakód, pl. insufficient_scope."},"message":{"type":"string","description":"Ember által olvasható ok. Validációs hibánál `<mezőút>: <ok>` alakú."}},"required":["code","message"]}},"required":["success","error"]}}}},"429":{"description":"rate_limited: A kulcs túllépte a percalapú keretet (olvasás 120/perc, írás 60/perc) vagy a napi 20 000 kérést.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false],"description":"Hibás válaszban mindig false."},"error":{"type":"object","properties":{"code":{"type":"string","description":"Gépi hibakód, pl. insufficient_scope."},"message":{"type":"string","description":"Ember által olvasható ok. Validációs hibánál `<mezőút>: <ok>` alakú."}},"required":["code","message"]}},"required":["success","error"]}}}},"500":{"description":"internal_error: Váratlan szerverhiba. FIGYELEM: a v1 felületen egy váratlan adatbázis-hiba NEM az egységes hibaburokban érkezik, hanem a keretrendszer alap 500-as válaszaként - erre a törzs-formátumra tehát ne építs feldolgozást.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false],"description":"Hibás válaszban mindig false."},"error":{"type":"object","properties":{"code":{"type":"string","description":"Gépi hibakód, pl. insufficient_scope."},"message":{"type":"string","description":"Ember által olvasható ok. Validációs hibánál `<mezőút>: <ok>` alakú."}},"required":["code","message"]}},"required":["success","error"]}}}}}}},"/blog/posts/{id}":{"get":{"operationId":"blog.get","tags":["blog"],"summary":"Egy blogposzt lekérdezése teljes tartalommal","description":"Egyetlen poszt teljes alakja azonosító alapján: a lista mezőin felül a HTML törzs (`contentHtml`), a SEO-adatok, az olvasási idő és a `websiteId`. Ez az egyetlen végpont, amelyik a poszt tartalmát is kiadja, és ez az egyetlen, amelyik a poszt `websiteId` mezőjét visszaadja. Az `{id}` értéke a `POST /blog/posts` válaszának vagy a lista `id` mezőjének a másolata; a rendszer az alakját nem vizsgálja, tehát bármilyen szöveget elfogad, és minden fel nem ismert értékre `404` a válasz. Más fiók posztjára `404` a válasz, pontosan ugyanaz, mint egy nem létező azonosítóra - a kettő szándékosan megkülönböztethetetlen. Kivezetés alatt: a v3-as utódja a `GET /api/v3/content/posts/{id}`, új integrációt arra építs.\n\nSzükséges scope: `content.readonly`. A v1 kulcson `blog.read` a neve.\n\nFelület: v1 (kivezetés alatt), a végpont a `/api/v1` előtag alatt él (lásd a művelet saját `servers` bejegyzését). Minden válasza `Deprecation: true` és `Sunset: 2027-02-03` fejlécet visel.\n\nSikeres válasz: `{ success: true, ... }` - a hasznos adat a `success` mező mellett, erőforrás-nevű kulcson.\n\nHibaválasz: `{ success: false, error: { code, message } }` - nincs `details[]` mező.","deprecated":true,"servers":[{"url":"https://prod.dynex.hu/api/v1","description":"A(z) v1 (kivezetés alatt) felület előtagja. Eddig szolgál ki: 2027-02-03."}],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Erőforrás-azonosító"},"required":true,"description":"Erőforrás-azonosító","name":"id","in":"path"}],"responses":{"200":{"description":"Sikeres válasz","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true],"description":"A v1 felület sikeres válaszainak állandó jelölője. Mindig `true`."},"post":{"type":"object","properties":{"id":{"type":"string","description":"A poszt állandó azonosítója. Ezt add át a `GET /blog/posts/{id}` végpontnak."},"title":{"type":"string","description":"A poszt címe, a beküldött alakban (a szélső szóközök levágva). Sosem üres és sosem `null`."},"slug":{"type":"string","description":"A poszt URL-barát azonosítója a weboldalon belül. Nem feltétlenül az, amit beküldtél: ékezet nélkülire alakul, és ütközés esetén `-2`, `-3` toldalékot kap."},"status":{"type":"string","enum":["draft","published","scheduled"],"description":"A poszt állapota: `draft`, `published` vagy `scheduled`. FIGYELEM: ez NEM azonos azzal, hogy a poszt látszik-e a nyilvános blogon. A `published` azonnal élő, a `publishedAt` értékétől FÜGGETLENÜL (a jövőbe tett `publishedAt` sem késlelteti, az csak megjelenített dátum). A `scheduled` poszt akkor válik élővé, amikor a `scheduledFor` időpont elmúlt - ezt a rendszer minden kérésnél újraszámolja, ütemezett feladat nélkül, ezért az állapot az adatbázisban VÉGLEG `scheduled` marad, a poszt akkor is, amikor már hónapok óta olvasható. Ha azt akarod tudni, látszik-e a poszt, a `status` és a `scheduledFor` mezőt EGYÜTT nézd: élő az, ami `published`, vagy `scheduled` múltbeli `scheduledFor` értékkel."},"excerpt":{"type":["string","null"],"description":"Rövid bevezető a listaoldalakhoz. `null`, ha nincs. Beküldéskor az `excerpt`, ennek hiányában a `description` mező tölti fel."},"coverImageUrl":{"type":["string","null"],"description":"A borítókép URL-je. Ha a beküldött képet sikerült a fiók saját tárhelyére átmásolni, ez egy hosszú lejáratú, aláírt tárhely-URL, egyébként a beküldött eredeti cím. `null`, ha nincs borítókép."},"authorName":{"type":["string","null"],"description":"A szerző neve szabad szövegként, ahogyan beküldték. `null`, ha nincs megadva. Ez NEM hivatkozás a `GET /blog/authors` listájára: az API-n létrehozott posztnak nincs szerző-azonosítója."},"tags":{"type":"array","items":{"type":"string"},"description":"A poszt címkéi. Mindig tömb, címke nélküli posztnál üres. A sorrend a beküldött sorrend."},"category":{"type":["object","null"],"properties":{"id":{"type":"string","description":"A kategória azonosítója. Ezzel nem lehet szűrni: a lista `category` paramétere nevet vagy slugot vár, nem azonosítót."},"name":{"type":"string","description":"A kategória megjelenített neve, ahogyan a poszt beküldésekor megadták."},"slug":{"type":"string","description":"A kategória URL-barát azonosítója a weboldalon belül."}},"required":["id","name","slug"],"description":"A poszt kategóriája. `null`, ha a poszt kategória nélkül jött létre, vagy ha a kategóriáját azóta törölték: a kategória törlése a posztokról előbb leveszi a hivatkozást, a poszt maga megmarad, csak kategória nélkül. Elárvult, feloldhatatlan kategória-hivatkozást tehát nem fogsz látni."},"publishedAt":{"type":["string","null"],"format":"date-time","description":"A megjelenés dátuma UTC-ben - megjelenített metaadat, nem kapcsoló. `null`, amíg nincs beállítva. Beküldéskor a `publishedAt` értéke kerül ide; ha nem küldtél ilyet, de a státusz `published`, akkor a létrehozás pillanata."},"scheduledFor":{"type":["string","null"],"format":"date-time","description":"Az ütemezett megjelenés időpontja UTC-ben. `null`, ha nincs ütemezve. A `scheduled` státuszú poszt ettől az időponttól látszik a nyilvános blogon."},"url":{"type":["string","null"],"description":"A poszt nyilvános címe. Bekötött saját domainnél `https://<domain>/blog/<slug>`, egyébként a Dynex platform-címén `<bázis-URL>/s/<fiók-slug>/blog/<slug>`. A GYAKORLATBAN mindig kitöltött: `null` csak akkor keletkezne, ha a weboldalhoz nincs saját domain ÉS a fiók slugja is üres, ilyen fiók viszont nem jön létre - a `null` a címszámoló függvény szignatúráját tükrözi, nem egy valós üzleti állapotot. A mező azt NEM garantálja, hogy a cím be is tölt, és ennek két oka lehet. (1) A nem élő (piszkozat vagy még ütemezett) poszt címe is kiszámolódik. (2) A platform-cím (`/s/<fiók-slug>/...`) mindig az ELSŐDLEGES weboldal blogját szolgálja ki, ezért egy másodlagos, saját domain nélküli weboldalra küldött poszt címe akkor is `404`-et ad, ha a poszt egyébként élő - ott csak a weboldalhoz bekötött saját domain ad működő címet."},"createdAt":{"type":"string","format":"date-time","description":"A poszt létrejöttének időpontja UTC-ben. A lista EZ SZERINT rendez, csökkenően."},"updatedAt":{"type":"string","format":"date-time","description":"Az utolsó módosítás időpontja UTC-ben. Az API-n létrehozott posztnál a létrehozás pillanatával egyezik, és csak a Dynex felületén végzett szerkesztés mozdítja el."},"websiteId":{"type":"string","description":"Annak a weboldalnak az azonosítója, amelyen a poszt megjelenik. Csak ez a végpont adja vissza, a lista nem. Ezt az értéket használd a `websiteId` szűrőkhöz."},"contentHtml":{"type":["string","null"],"description":"A poszt teljes HTML törzse, pontosan úgy, ahogyan tárolva van: a rendszer nem tisztítja, nem alakítja és nem egészíti ki. `null` is lehet - a Dynex szerkesztőjében blokkokból összerakott posztoknak nincs HTML törzsük, azok tartalmát ez az API nem adja ki. Az API-n beküldött posztnál ez mindig kitöltött (a beküldött HTML, szélein levágott szóközökkel)."},"seo":{"type":["object","null"],"additionalProperties":{},"description":"A poszt SEO-mezői szabad alakú objektumként. Az API-n beküldött posztnál `title` és `description` kulcsot tartalmazhat; a Dynex szerkesztőjéből ettől eltérő kulcsok is kerülhetnek bele, ezért ne várj rögzített alakot. `null`, ha nincs SEO-adat."},"readingTimeMinutes":{"type":["integer","null"],"description":"Becsült olvasási idő percben. Az API-n beküldött posztnál a HTML szöveges tartalmából számolódik, körülbelül 200 szó/perccel, legalább 1 perc. `null` is lehet a máshonnan létrejött posztoknál."}},"required":["id","title","slug","status","excerpt","coverImageUrl","authorName","tags","category","publishedAt","scheduledFor","url","createdAt","updatedAt","websiteId","contentHtml","seo","readingTimeMinutes"]}},"required":["success","post"]}}}},"401":{"description":"unauthorized: Hiányzó, hibás formátumú, ismeretlen, visszavont, kikapcsolt vagy lejárt kulcs. A v1 a `dxk_` és a `dxp_` előtagú kulcsot is elfogadja, minden más előtagot azonnal elutasít. A `dxp_` tokennek lejárati ideje és ki-be kapcsolója is van, tehát egy korábban működő token ettől is elbukhat.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false],"description":"Hibás válaszban mindig false."},"error":{"type":"object","properties":{"code":{"type":"string","description":"Gépi hibakód, pl. insufficient_scope."},"message":{"type":"string","description":"Ember által olvasható ok. Validációs hibánál `<mezőút>: <ok>` alakú."}},"required":["code","message"]}},"required":["success","error"]}}}},"403":{"description":"insufficient_scope: A kulcs él, de nincs meg rajta a végponthoz kért scope. Az üzenet megnevezi, melyik hiányzik. A kulcson lévő `*` mindent megad. feature_not_available: A fiók előfizetése nem tartalmazza az API-hozzáférést (`api_access` funkció). forbidden: A hívó IP-címe nincs rajta a token allowlistáján. Csak `dxp_` tokennél fordulhat elő, és csak akkor, ha a tokenhez egyáltalán van allowlista megadva.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false],"description":"Hibás válaszban mindig false."},"error":{"type":"object","properties":{"code":{"type":"string","description":"Gépi hibakód, pl. insufficient_scope."},"message":{"type":"string","description":"Ember által olvasható ok. Validációs hibánál `<mezőút>: <ok>` alakú."}},"required":["code","message"]}},"required":["success","error"]}}}},"404":{"description":"not_found: Az erőforrás nem létezik EBBEN a fiókban. Egy másik fiókhoz tartozó azonosító is ezt adja - a kettő szándékosan megkülönböztethetetlen.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false],"description":"Hibás válaszban mindig false."},"error":{"type":"object","properties":{"code":{"type":"string","description":"Gépi hibakód, pl. insufficient_scope."},"message":{"type":"string","description":"Ember által olvasható ok. Validációs hibánál `<mezőút>: <ok>` alakú."}},"required":["code","message"]}},"required":["success","error"]}}}},"429":{"description":"rate_limited: A kulcs túllépte a percalapú keretet (olvasás 120/perc, írás 60/perc) vagy a napi 20 000 kérést.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false],"description":"Hibás válaszban mindig false."},"error":{"type":"object","properties":{"code":{"type":"string","description":"Gépi hibakód, pl. insufficient_scope."},"message":{"type":"string","description":"Ember által olvasható ok. Validációs hibánál `<mezőút>: <ok>` alakú."}},"required":["code","message"]}},"required":["success","error"]}}}},"500":{"description":"internal_error: Váratlan szerverhiba. FIGYELEM: a v1 felületen egy váratlan adatbázis-hiba NEM az egységes hibaburokban érkezik, hanem a keretrendszer alap 500-as válaszaként - erre a törzs-formátumra tehát ne építs feldolgozást.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false],"description":"Hibás válaszban mindig false."},"error":{"type":"object","properties":{"code":{"type":"string","description":"Gépi hibakód, pl. insufficient_scope."},"message":{"type":"string","description":"Ember által olvasható ok. Validációs hibánál `<mezőút>: <ok>` alakú."}},"required":["code","message"]}},"required":["success","error"]}}}}}}}},"webhooks":{}}