Tovább a tartalomhoz
ÁrakAlkalmazás

API referencia

Ez az oldal az OkosMunkalap REST API minden végpontját leírja kéréssel, válasszal és példákkal. A hitelesítésről a Hitelesítés és kulcsok oldal szól.

  • Alap URL: https://api.okosmunkalap.hu
  • Verzió előtag: minden végpont a /v1 alatt van (pl. https://api.okosmunkalap.hu/v1/worksheets).
  • Adatformátum: kérés és válasz egyaránt JSON (Content-Type: application/json).
  • Karakterkódolás: UTF-8.
Eset Formátum
Egy erőforrás { "data": { ... } }
Lista { "data": [ ... ], "pagination": { ... } }
Hiba { "error": { "code", "message", "status", "requestId", "details"? } }
Figyelmeztetés (nem blokkoló) a data mellett { "warnings": [ { "code", "message" } ] }

A nem kitöltött (opcionális) mezők kimaradnak a válaszból. Az API nem ad vissza null értéket helyettük, egyszerűen nincs jelen a kulcs.

Fejléc Kötelező Leírás
Authorization igen Bearer <kulcs>, lásd Hitelesítés
Content-Type POST/PATCH-nél application/json
X-API-Version nem a kulcs alapértelmezett verziójának felülírása erre a kérésre
Idempotency-Key nem POST-nál a biztonságos újrapróbáláshoz, lásd Idempotencia
Fejléc Mikor Leírás
X-Request-Id minden válaszban a kérés egyedi azonosítója (req_...); add meg hibabejelentéskor
X-API-Version-Used sikeres hitelesítés után a ténylegesen alkalmazott API verzió
X-RateLimit-Limit sikeres hitelesítés után a percenkénti kéréskorlát
X-RateLimit-Remaining sikeres hitelesítés után a hátralévő kérések száma az aktuális percben
X-RateLimit-Reset sikeres hitelesítés után a percablak nullázódásának ideje (Unix epoch másodperc)
Retry-After csak 429 válasznál hány másodperc múlva próbáld újra

A X-Request-Id minden válaszban jelen van. A verzió és a kéréskorlát fejlécek csak a sikeres hitelesítés után kerülnek be, ezért egy 401 (érvénytelen kulcs) válaszban nem garantáltak.

Fontos aszimmetria a kérés és a válasz között:

  • Kérésben a dátum mezők (pl. scheduledDate, completedAt) ISO 8601 alapú stringek. Az elfogadott alak: dátum ÉÉÉÉ-HH-NN (pl. 2026-06-15), opcionálisan idő T vagy szóköz elválasztóval (óó:pp, majd opcionálisan :ss és .ezred), opcionálisan időzóna (Z vagy +óó:pp). Időzóna nélkül az értelmezés nem garantáltan UTC, ezért erősen ajánlott a teljes UTC alak: "2026-06-15T08:00:00Z". A nem ISO formátum (pl. 15.06.2026, 06/15/2026, tomorrow) 400 hibát ad.

  • Válaszban a dátum mezők Firestore időbélyeg objektumként érkeznek, két mezővel:

    "scheduledDate": { "_seconds": 1781510400, "_nanoseconds": 0 }

    A _seconds a Unix epoch másodperc. Ebből bármely nyelvben előállítható a dátum (pl. JavaScriptben new Date(_seconds * 1000)).

Minden kulcsra kétféle korlát vonatkozik: egy percenkénti kéréskorlát és egy havi keret. Az értékek a fiók csomagjától függnek (lásd az Áttekintés táblázatát). AI célú kulcson mindkét érték feleződik.

A sikeres hitelesítés utáni válaszok tartalmazzák az X-RateLimit-Limit, X-RateLimit-Remaining és X-RateLimit-Reset fejléceket, így a kliens követheti a fogyását. Egy 401 (érvénytelen kulcs) válaszon ezek nem garantáltak, mert a hitelesítés a kéréskorlát-ellenőrzés előtt fut.

A korlát túllépésekor az API 429 hibát ad és beállítja a Retry-After fejlécet:

  • a percenkénti korlát túllépése: RATE_LIMIT_EXCEEDED, details: { limit, retryAfter },
  • a havi keret kimerülése: QUOTA_EXCEEDED, details: { monthlyQuota, retryAfter }.

Ajánlott a Retry-After szerinti várakozás, majd újrapróbálás (exponenciális visszalépéssel).

A POST kérések biztonságosan megismételhetők az Idempotency-Key fejléccel. Ez megakadályozza, hogy egy hálózati hiba miatti újrapróbálás kétszer hozzon létre ugyanazt az erőforrást.

  • Adj meg egy egyedi kulcsot kérésenként (pl. UUID), legfeljebb 255 karakter.
  • Ha ugyanazzal a kulccsal és ugyanazzal a kéréstörzzsel próbálkozol újra, az API nem futtatja le újra a műveletet, hanem visszajátssza a korábbi választ.
  • Ha ugyanazt a kulcsot eltérő kéréstörzzsel használod, az API 409 hibát ad IDEMPOTENCY_KEY_REUSE_DIFFERENT_BODY kóddal.
  • Ha egy azonos kulcsú kérés épp feldolgozás alatt van, a párhuzamos kérés 409 hibát kap IDEMPOTENCY_KEY_IN_USE kóddal.

Csak a sikeres (2xx/3xx) válaszok kerülnek gyorsítótárba, és a gyorsítótár 24 óráig él. A hibás válaszok (pl. 404, 409) nem ragadnak be, ezért az állapotfüggő hibák után az újrapróbálás ténylegesen újra lefut.

Az újrafutás ilyenkor sem hoz létre második rekordot: a létrehozó végpontok az erőforrás azonosítóját magából a kérésből képzik, ezért az ismételt hívás ugyanarra az erőforrásra fut rá, és a már létrejöttet adja vissza. Ez akkor is véd, ha az előző kérés még hiba előtt írt.

Ebből következik, hogy egy kulcs ugyanahhoz a végponthoz véglegesen egy erőforrást jelent, a 24 órás gyorsítótár lejárta után is. Ha szándékosan új erőforrást hozol létre, mindig új kulcsot küldj.

A listavégpontok (jelenleg a GET /v1/worksheets) kurzor alapú lapozást használnak:

  • limit: az oldal mérete, 1 és 100 között (alapértelmezés: 20).
  • starting_after: az előző oldal pagination.nextCursor értéke.

A válasz pagination objektuma:

"pagination": { "hasMore": true, "limit": 20, "nextCursor": "eyJ..." }

Ha hasMore igaz, a nextCursor jelen van, és átadható a következő kérés starting_after paramétereként. A kurzor a lekérdezés szűrőkészletéhez kötött: ha lapozás közben módosítod a szűrőket (pl. más status), az API 400 hibát ad INVALID_CURSOR kóddal. Lapozáskor tartsd változatlanul a szűrőket.

Minden hiba ugyanazt a borítékot adja:

{
"error": {
"code": "INVALID_REQUEST_BODY",
"message": "Emberi olvasásra szánt üzenet (a kódra ágazz, ne erre).",
"status": 400,
"requestId": "req_a1b2c3d4e5f6a7b8",
"details": { }
}
}
  • A code gépi feldolgozásra való: erre ágazz el a kódodban, ne az üzenet szövegére.
  • A message magyar nyelvű, emberi olvasásra.
  • A status megegyezik a HTTP státuszkóddal.
  • A requestId a kérés azonosítója; add meg, ha hibát jelentesz nekünk.
  • A details opcionális, és kódfüggő kiegészítő adatot tartalmaz (pl. a hiányzó jogosultság nevét, a validációs hibák listáját).

Validációs hibánál (INVALID_REQUEST_BODY) a details.issues tömb mezőnként sorolja a problémát:

{
"error": {
"code": "INVALID_REQUEST_BODY",
"message": "A kérés törzse érvénytelen.",
"status": 400,
"requestId": "req_...",
"details": {
"issues": [
{ "path": "name", "message": "A név kötelező" },
{ "path": "taxNumber", "message": "Érvénytelen adószám (formátum: 12345678-1-42)" }
]
}
}
}

A HTTP státuszkód a hiba kategóriáját jelzi:

HTTP Jelentés Példa kódok
400 a kérés hibás INVALID_REQUEST_BODY, MISSING_REQUIRED_FIELD, INVALID_CURSOR, EXTERNAL_SYSTEM_NOT_CONFIGURED, EXTERNAL_SYSTEM_AMBIGUOUS, EXTERNAL_ID_FIELD_MISMATCH, EXTERNAL_ID_NOT_SINGLE_TOKEN
401 hitelesítés sikertelen INVALID_API_KEY
403 nincs jogosultság vagy a csomag nem engedi MISSING_PERMISSION, KEY_EXPIRED, EXTERNAL_NAMESPACE_FORBIDDEN, MODULE_NOT_AVAILABLE, QUOTE_LIMIT_EXCEEDED
404 nem található CUSTOMER_NOT_FOUND, WORKSHEET_NOT_FOUND, QUOTE_NOT_FOUND, TEAM_MEMBER_NOT_FOUND, NOT_FOUND
409 ütközés DUPLICATE_EXTERNAL_ID, EXTERNAL_ID_AMBIGUOUS, CONFIRMATION_REQUIRED, IDEMPOTENCY_KEY_IN_USE
429 korlát túllépve RATE_LIMIT_EXCEEDED, QUOTA_EXCEEDED
500 szerveroldali hiba INTERNAL_ERROR

A teljes hibakód listát, minden kódhoz a gyakori kiváltó okkal és a javasolt teendővel, a Hibakódok oldal tartalmazza.

Az ügyfél címe és a munkalap munkavégzési címe ugyanazt a szerkezetet használja. Strukturáltan (zip, city, street, country) vagy szabad szövegként (fullText) is megadható. Minden mező opcionális.

Mező Típus Megkötés
zip string max. 20
city string max. 100
street string max. 200
country string max. 100
fullText string max. 300 (szabad szöveges cím)

Szabad szöveges cím feldolgozása: ha a cím csak fullText-et tartalmaz (strukturált mező nélkül), és magyar címről van szó (a country üres vagy Magyarország), a rendszer megkísérli a szöveg strukturálását a tipikus magyar címformátumok alapján (pl. 1152 Budapest, Telek utca 7-9. vagy 1111 Budapest Példa u. 14.). Sikeres feldolgozáskor a zip, city és street mezők kitöltődnek, az eredeti szöveg a fullText-ben referenciaként megmarad, és az ügyfél addressParseStatus mezője parsed_from_fulltext lesz — figyelmeztetés ilyenkor nincs. Ha a szöveg nem strukturálható egyértelműen (nincs 4 jegyű irányítószám az elején, vagy a település/utca határ nem állapítható meg), a cím változatlanul, szabad szövegként tárolódik (unstructured), és a válasz ADDRESS_UNSTRUCTURED figyelmeztetést ad. Ha bármely strukturált mezőt megadod, a rendszer nem módosítja azokat (nincs feldolgozási kísérlet).

A munkalap items tömbjének eleme:

Mező Típus Kötelező Alapértelmezés Megkötés
description string igen a tétel megnevezése, max. 500
type enum nem other material, labor, travel, other, section
quantity number nem 1 nem negatív
unit string nem db max. 20
unitPrice number nem bruttó egységár, nem negatív
vatRate number nem 27 0, 5, 18 vagy 27
note string nem max. 1000
isWarranty boolean nem garanciális tétel-e
warrantyDuration number nem garancia időtartama, egész szám (pl. 12)
warrantyUnit string nem month (hónap) vagy year (év)
warrantyNote string nem garancia megjegyzés, max. 2000

A tétel id mezőjét nem kell (és nem is lehet) megadni: a szerver generálja. A totalPrice mezőt a szerver számolja (unitPrice × quantity, egész forintra kerekítve). A garancia mezők a válaszban csak akkor jelennek meg, ha a tétel garanciális (isWarranty: true).

Több eszközös szerviz munkalapon a válasz tételein megjelenik a deviceLocalId mező is. Ez a devices tömb megfelelő elemének id mezőjére mutat, tehát ebből derül ki, melyik átvett eszközhöz tartozik az adott sor. Eszközhöz nem kötött tételen a mező kimarad.

A status mező érvényes beépített értékei:

Érték Jelentés
draft Piszkozat
quote_generated Árajánlat készült belőle
worksheet_generated Munkalap készült a felmérésből
survey_done Felmérés lezárva (régi)
in_progress Folyamatban
completed Befejezve
sent Elküldve
invoiced Számlázva
partially_invoiced Részben számlázva
cancelled Visszavonva

A fiók egyedi státuszokat is használhat; ezek custom_ előtaggal jelennek meg (pl. custom_fuggoben). A teljes minta: ^custom_[\p{L}\p{N}_-]{1,80}$ (a custom_ után 1 és 80 közötti Unicode betű, szám, kötőjel vagy aláhúzás). Munkalap létrehozásakor csak a draft és az in_progress állítható be; a többi állapotba a PATCH /v1/worksheets/{id}/status végponttal lehet lépni.

Egy munkalap kollégákhoz rendelhető, szerepkörrel. A hozzárendelés két helyen adható meg: a POST /v1/worksheets kérés assignments mezőjében (már létrehozáskor), vagy utólag a POST /v1/worksheets/{id}/assign végponttal.

Egy hozzárendelés két adatot tartalmaz:

Mező Típus Kötelező Leírás
userId string igen a csapattag azonosítója a GET /v1/team-members válaszából, max. 128
role enum nem szerepkör, alapértelmezés: lead

Az érvényes szerepkörök:

Érték Jelentés Több fő?
lead Fő felelős nem
surveyor Felmérő igen
quote_maker Árajánlatkészítő nem
coordinator Munkaszervező nem
installer Kivitelező igen
contact Kapcsolattartó nem

A hívó csak azonosítót ad, a megjelenített nevet a szerver tölti ki a csapattag adataiból: így a munkalap fejlécén nem jelenhet meg hamis név. A hozzárendelt kolléga a szokásos értesítést kapja.

A szerver a következőket ellenőrzi (a hívás ilyenkor egyetlen hozzárendelést sem állít be):

Eset Válasz
nem létező vagy nem aktív csapattag 404 (TEAM_MEMBER_NOT_FOUND)
a munkaterülethez nem tartozik csapat 400 (INVALID_REQUEST_BODY)
a szerepkör ki van kapcsolva a munkaterületen 400 (INVALID_REQUEST_BODY)
ugyanaz a kolléga ugyanabban a szerepkörben kétszer 400 (INVALID_REQUEST_BODY)
egyfős szerepkörhöz (pl. lead) két kolléga 400 (INVALID_REQUEST_BODY)
kiszállás-konténer munkalap 400 (INVALID_REQUEST_BODY)

A kiszállásokat tartalmazó (konténer) munkalapra azért nem rendelhető kolléga, mert a munka és így a felelős is az egyes kiszállásokon él: a hozzárendelést a kiszállás munkalapján add meg.

A válaszban a munkalap assignments tömbje a hozzárendeléseket role, userId és userName hármasként adja vissza (hozzárendelés nélküli munkalapon a mező kimarad).

Jogosultság: a userId feloldásához (GET /v1/team-members) team:read kell. A létrehozáskori assignments a worksheets:create mellett szintén team:read-et igényel, mert a válasz a kolléga nevét is tartalmazza. Az utólagos hozzárendelés (POST /v1/worksheets/{id}/assign) worksheets:write jogosultságú.

Cél-névtér az externalSystem paraméterrel

Szekció neve “Cél-névtér az externalSystem paraméterrel”

Ha a kulcshoz több külső rendszer névtér tartozik (lásd Hitelesítés), az externalSystem paraméterrel adhatod meg, melyik névtérre vonatkozzon a hívás. Egyetlen névteres kulcson nincs rá szükség: a hívás magától ahhoz az egy névtérhez kötődik.

A paraméter alakja a művelettől függ:

  • Íráskor (külső azonosító létrehozása) a POST /v1/customers és a POST /v1/worksheets (a customer.createIfMissing / lookupExternalId ág) kéréstörzsében opcionális externalSystem mező. A cél-névtér feloldása:

    Helyzet Eredmény
    externalSystem megadva, és a kulcs névterei közt van abba a névtérbe ír
    externalSystem megadva, de a kulcs névterei közt nincs 403 (EXTERNAL_NAMESPACE_FORBIDDEN)
    externalSystem kihagyva, van elsődleges névtér az elsődleges névtérbe ír
    externalSystem kihagyva, nincs elsődleges, de a kulcsnak egy névtere van abba az egy névtérbe ír
    externalSystem kihagyva, nincs elsődleges, és több névtér van 400 (EXTERNAL_SYSTEM_AMBIGUOUS)
  • Olvasáskor (külső azonosító / telefon alapú keresés) a GET /v1/customers (?externalId=, ?phone=) és a GET /v1/worksheets (?customerExternalId=) opcionális externalSystem query paramétere. Ha megadod, a keresés csak abban a névtérben fut (ha a névtér nincs a kulcson, 403 EXTERNAL_NAMESPACE_FORBIDDEN); ha kihagyod, a kulcs minden névterében keres. Ha a keresés két különböző ügyfélre is illeszkedik, 409 (EXTERNAL_ID_AMBIGUOUS) — ezt a célzott externalSystem-mel kerülöd el.
    Megjegyzés a telefonos kereséshez (?phone=): az externalSystem csak external_system hatókörű kulcson szűkít. Az all_account hatókörű kulcs a telefont a teljes fiókon keresi (az externalSystem-et figyelmen kívül hagyja), és több azonos telefonszámú ügyfélnél egyet ad vissza.

Az externalSystem értéke ugyanazt a formátumot követi, mint a névtér neve: ^[a-z0-9_-]{1,64}$ (a rendszer kisbetűsíti).

A külső azonosító (externalId) egy névtéren belül pontosan egy ügyfelet azonosít, és ezt az egyediséget a rendszer írásidőben kényszeríti ki — nem a kliensnek kell biztosítania.

  • Íráskor. Ha olyan externalId-t próbálsz egy ügyfélhez rendelni, amely az adott névtérben már másik ügyfélhez tartozik, a hívás 409 (DUPLICATE_EXTERNAL_ID) hibát ad — a rendszer nem köt két ügyfélhez ugyanazt az azonosítót. Ezért ha a kezdetektől az API-n viszed fel az azonosítókat, duplikátum nem alakulhat ki.
  • A DUPLICATE_EXTERNAL_ID kezelése: match-or-create, nem ügyfél-választó. Nem kell választót építened. Ha az azonosító már foglalt, kérdezd le a meglévő ügyfelet a GET /v1/customers?externalId=... hívással (megmondja, melyik ügyfélé az azonosító), és azt frissítsd új létrehozás helyett. A POST /v1/worksheets ügyfél-referenciája (lookupExternalId + opcionális createIfMissing) ezt a match-or-create logikát beépítve hozza: ha a keresés talál, a meglévő ügyfélre dolgozik, különben létrehozza.

A telefonszám más eset. A ?phone= keresőkulcs nem egyedi — egy számhoz több ügyfél is tartozhat legitim módon (pl. cég és kapcsolattartó, vagy több telephely). A telefon ezért nem azonosító, csak kényelmi keresés:

  • all_account hatókörű kulcson a ?phone= az első találatot adja vissza.
  • external_system hatókörű kulcson, ha több in-scope ügyfélre illeszkedik, 409 (EXTERNAL_ID_AMBIGUOUS) — szűkítsd az externalSystem paraméterrel. Megbízható, egyértelmű azonosításhoz használj externalId-t.

Meglévő adat átállásakor és visszatérő ütközéseknél. Ha egy korábban szabad mezőben (pl. customFields) tárolt értéket emelsz át külső azonosítóvá, a régi adatban ugyanaz az érték több ügyfélnél is szerepelhet, amit az API egyedisége korábban nem védett. Az átálláskor a rendszer az egyedi értékeket automatikusan beköti, az ütköző (több élő ügyfélre eső) értékeket viszont egyetlen ügyfélhez sem rendeli. Amíg egy érték így duplikált, a GET /v1/customers?externalId=... és a POST /v1/worksheets (lookupExternalId / createIfMissing) erre az értékre 409 (EXTERNAL_ID_AMBIGUOUS) hibát ad, és nem hoz létre munkalapot vagy új ügyfelet. Így soha nem kötődik munkalap rossz ügyfélhez. Ez nem csak egyszeri adatrendezés: ha később ugyanaz az azonosító ismét két élő ügyfélre illeszkedik (például egy azonosítót átadnak egy másik ügyfélnek), a rendszer ugyanígy blokkolja. Amint az ütközés a forrásnál feloldódik (egy azonosító = egy ügyfél), a rendszer automatikusan az immár egyedi ügyfélhez köti az értéket, külön beavatkozás nélkül.

Több azonosító egy mezőben (token-szintű keresés)

Szekció neve “Több azonosító egy mezőben (token-szintű keresés)”

Előfordul, hogy egy ügyfélhez ugyanabból az azonosító-típusból több érték tartozik (például több távfelügyeleti ügyfélszám egyetlen „Távfelügyeleti Ügyfélszám“ mezőben: 3158/3159/3160). Ha a névtérhez rendelt egyedi mező „Több azonosító egy mezőben“ módban van (a mező szerkesztőjében kapcsolható), a rendszer a mező értékét azonosítókra bontja, és minden azonosító önállóan kereshető: a GET /v1/customers?externalId=3159 a fenti ügyfelet adja vissza.

Elválasztók és korlátok.

  • Elválasztó karakterek: / (perjel), , (vessző), ; (pontosvessző); egymás után többől álló elválasztó-sorozat egynek számít. A szóköz nem elválasztó (a B 12 egyetlen azonosító), az azonosítók eleji és végi szóközei lemaradnak.
  • Legfeljebb 20 azonosító szerepelhet egy mezőben; egy azonosító legfeljebb 255 karakter, a mező teljes hossza legfeljebb 1000 karakter. A korláton túli érték API-n 400 hibát ad; az alkalmazásban mentett túl hosszú érték megmarad a mezőben, de nem válik kereshetővé (az alkalmazás jelzi ezt az ügyfél adatlapján).
  • Az ismétlődő azonosítók egy mezőn belül egyszer számítanak.
  • Ha a névtér nem „több azonosító“ módú (alapértelmezés), az érték változatlanul, elválasztó karakterekkel együtt EGY azonosító. A 001/2026 formátumú azonosítók így biztonságban vannak.

Egyediség azonosítónként. Az Egyediség és duplikátumok szabályai azonosítónként (tokenenként) érvényesek: egy azonosító egy névtérben pontosan egy ügyfélé. Ha egy mező több azonosítója közül némelyik másik élő ügyfélnél is szerepel, az ütköző azonosítók egyik ügyfélhez sem kötődnek (rájuk a keresés 409 EXTERNAL_ID_AMBIGUOUS), a többi azonosító viszont normálisan kereshető. Egy ütköző érték nem bénítja meg a mező többi azonosítóját.

externalIds és externalIdValues a válaszban. Az ügyfél-válasz két mezőt ad:

Mező Jelentés
externalIds a mező nyers értéke névterenként (amit a felhasználó a mezőben lát, pl. "3158/3159/3160"); tükör, nem kereshetőségi ígéret
externalIdValues a ténylegesen kereshető azonosítók névterenként, listaként (pl. ["3158", "3159", "3160"]); üres lista = a mezőben van érték, de egyetlen azonosító sem kereshető (pl. mindegyik ütközik)
{
"externalIds": { "monitoring": "3158/3159/3160" },
"externalIdValues": { "monitoring": ["3158", "3159", "3160"] }
}

Kereséshez, összevetéshez mindig az externalIdValues-t használd; az externalIds a megjelenítéshez való.

Keresés mindig EGY azonosítóval. A GET /v1/customers?externalId= és a POST /v1/worksheets (lookupExternalId) paramétere mindig egyetlen azonosító. „Több azonosító“ módú névtérben elválasztó karaktert (/, ,, ;) tartalmazó keresőérték 400 hibát ad; a teljes felsorolásra (3158/3159/3160) nem lehet keresni, csak az egyes azonosítókra.

Írás.

  • POST /v1/customers: az externalId (egy azonosító) és a névtérhez rendelt egyedi mező (customFields, a teljes felsorolás) együtt is küldhető. Ilyenkor az externalId-nak a mező azonosítói között kell lennie, különben 400 (EXTERNAL_ID_FIELD_MISMATCH).
  • PATCH /v1/customers/{id} az egyedi mezőn: a mező új felsorolása egyben érvényesül. Ha az újonnan bekerülő azonosítók bármelyike másik élő ügyfélé, a teljes írás 409 (DUPLICATE_EXTERNAL_ID), és semmi sem módosul.
  • POST /v1/worksheets createIfMissing: az új ügyfél a megadott EGY azonosítóval jön létre; a további azonosítókat utólag a mező PATCH-ével adhatod hozzá.

A kulcs és a kapcsolat ellenőrzése. Nem igényel külön jogosultságot (csak érvényes kulcsot).

Terminál
curl https://api.okosmunkalap.hu/v1/ping \
-H "Authorization: Bearer omk_live_a1b2c3d..."
{
"data": {
"pong": true,
"keyPrefix": "omk_live_a1b2c3d",
"permissions": ["customers:read", "worksheets:create"],
"apiVersion": "2026-06-15",
"dataScope": "external_system",
"requestId": "req_a1b2c3d4e5f6a7b8"
}
}

A dataScope mező a válaszban csak akkor jelenik meg, ha a kulcson explicit be van állítva (mint minden opcionális mező, üres értéknél kimarad). A kulcs tényleges adat hatóköréről lásd a Hitelesítés oldalt.


Új ügyfél létrehozása. Jogosultság: customers:create.

Kéréstörzs:

Mező Típus Kötelező Megkötés
name string igen max. 100
phone string nem max. 30
email string nem érvényes email
company string nem max. 100
taxNumber string nem formátum: 12345678-1-42
taxCategory enum nem domestic, eu_reverse_charge, non_eu_export
address objektum nem lásd Cím
externalId string nem a kulcs külső rendszer névterébe kerül (max. 255)
externalSystem string nem a cél-névtér, ha a kulcsnak több névtere van; lásd Cél-névtér (csak externalId mellett értelmes)
customFields objektum nem { "mezőId": "érték" }, lásd GET /v1/custom-fields
siteContactName string nem helyszíni kapcsolattartó neve, max. 100
siteContactPhone string nem helyszíni kapcsolattartó telefonja, max. 30
siteContactEmail string nem helyszíni kapcsolattartó email címe (email formátum)
notes string nem max. 500
isVip boolean nem

external_system hatókörű kulcsnál az externalId kötelező.

Ha a kulcsnak több névtere van, az externalId az externalSystem mezővel megadott névtérbe kerül (vagy az elsődlegesbe, ha kihagyod). Több névtér, elsődleges nélkül, explicit externalSystem nélkül 400 (EXTERNAL_SYSTEM_AMBIGUOUS). Tiltott névtér 403 (EXTERNAL_NAMESPACE_FORBIDDEN). Lásd Cél-névtér. Ha a névtérhez egyedi mező (customFields) van rendelve, az externalId és az egyedi mező értéke nem térhet el — különben 400 (EXTERNAL_ID_FIELD_MISMATCH).

Terminál
curl -X POST https://api.okosmunkalap.hu/v1/customers \
-H "Authorization: Bearer omk_live_a1b2c3d..." \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 7f1c2e9a-..." \
-d '{
"name": "Példa Kft.",
"phone": "+36 30 123 4567",
"email": "info@pelda.hu",
"taxNumber": "12345678-1-42",
"externalId": "CUST-9001",
"address": { "zip": "1051", "city": "Budapest", "street": "Fő utca 1." }
}'

Válasz (201):

{
"data": {
"id": "abc123",
"name": "Példa Kft.",
"phone": "+36 30 123 4567",
"email": "info@pelda.hu",
"taxNumber": "12345678-1-42",
"address": { "zip": "1051", "city": "Budapest", "street": "Fő utca 1." },
"addressParseStatus": "structured",
"externalIds": { "monitoring": "CUST-9001" },
"url": "https://app.okosmunkalap.hu/customers/abc123"
}
}

A példa a beküldött mezőket tükrözi. A válasz a következő mezőket adhatja vissza (a ki nem töltöttek a borítékelv szerint kimaradnak — lásd Válaszformátum):

Mező Mikor szerepel Leírás
id mindig az OkosMunkalap belső ügyfél azonosítója
name mindig az ügyfél neve
phone, email, company, taxNumber ha kitöltött törzsadatok
taxCategory ha kitöltött domestic, eu_reverse_charge vagy non_eu_export
address ha van cím a Cím szerkezet kitöltött mezői
addressParseStatus ha van cím structured (strukturált irányítószám + település), parsed_from_fulltext (szabad szövegből kinyert strukturált cím) vagy unstructured (csak szabad szöveg / hiányos)
externalIds ha van { "névtér": "külső azonosító" }; external_system hatókörnél csak a kulcs saját névtere
customFields ha van { "mezőId": "érték" }
isVip ha be van állítva VIP jelölés
url mindig az ügyfél megnyitása az alkalmazásban

A siteContactName, siteContactPhone, siteContactEmail és notes mezők nem szerepelnek a válaszban (lásd lent, csak írható mezők).

Ha a cím csak szabad szöveggel (fullText) érkezett és a szabad szöveges cím feldolgozása nem járt sikerrel, a válasz warnings tömböt tartalmaz ADDRESS_UNSTRUCTURED kóddal: a művelet sikerült, de számlázáshoz strukturált irányítószám és település szükséges. Sikeres feldolgozáskor nincs figyelmeztetés, és a válasz már a kinyert zip / city / street mezőket adja vissza (addressParseStatus: "parsed_from_fulltext").

A siteContactName, siteContactPhone, siteContactEmail és notes mezők csak írhatók: a kérésben megadhatók, de az ügyfél válaszában (és a webhook data mezőjében) nem jelennek meg.


Ügyfél keresése külső azonosító vagy telefonszám alapján. Jogosultság: customers:read. Add meg az egyik query paramétert. Ha mindkettőt megadod, az externalId élvez elsőbbséget.

Query paraméter Leírás
externalId a kulcs névterében tárolt külső azonosító (pontos egyezés)
phone telefonszám; a rendszer E.164 formátumra normalizálja, és úgy keres
externalSystem opcionális: a keresett névtér, ha a kulcsnak több van; lásd Cél-névtér

A phone keresésnél a +36..., 06... és 0036... alakok mind ugyanarra az ügyfélre oldódnak fel.

Több névtér és egyértelműség. Ha a kulcsnak több névtere van, a keresés alapból minden névterében fut. Ha a keresés (akár az externalId több névtéren, akár ugyanaz a phone több ügyfélen) két különböző ügyfélre illeszkedik, az API 409 (EXTERNAL_ID_AMBIGUOUS) hibát ad, nem választ önkényesen. A phone-keresésnél ez a 409 a névtér-szűrt, external_system hatókörű ágra vonatkozik; az all_account hatókörű kulcs a phone-ra az első találatot adja vissza (nem ütközik). Ilyenkor szűkítsd a keresést a célzott externalSystem paraméterrel (ekkor csak abban a névtérben keres). Ugyanaz az ügyfél több névtéren (közös érték) nem ütközés. Egyetlen névteres kulcson externalId-vel ez a helyzet nem fordul elő; egyedi azonosításhoz a külső azonosító megbízhatóbb a telefonszámnál.

Terminál
curl "https://api.okosmunkalap.hu/v1/customers?externalId=CUST-9001" \
-H "Authorization: Bearer omk_live_a1b2c3d..."
Terminál
curl "https://api.okosmunkalap.hu/v1/customers?phone=06301234567" \
-H "Authorization: Bearer omk_live_a1b2c3d..."

Válasz: egyetlen ügyfél a data mezőben (mint a POST /v1/customers-nél). Ha nincs találat (vagy a hatókörön kívül esik), 404 (CUSTOMER_NOT_FOUND). Ha egyik paramétert sem adod meg, 400 (MISSING_REQUIRED_FIELD). Ha a keresés több in-scope ügyfélre illeszkedik (external_system hatókörű kulcson), 409 (EXTERNAL_ID_AMBIGUOUS) — add meg az externalSystem paramétert. (all_account hatókörű kulcson a phone-keresés az első találatot adja vissza.)


Egy ügyfél lekérdezése az OkosMunkalap belső azonosítója alapján. Jogosultság: customers:read.

Terminál
curl https://api.okosmunkalap.hu/v1/customers/abc123 \
-H "Authorization: Bearer omk_live_a1b2c3d..."

Válasz: az ügyfél a data mezőben. Hatókörön kívüli vagy nem létező azonosító esetén 404 (CUSTOMER_NOT_FOUND).


Meglévő ügyfél részleges módosítása. Jogosultság: customers:write. Csak a megadott mezők módosulnak (sparse update); a kéréstörzs mezői ugyanazok, mint a POST /v1/customers-nél, de mind opcionális.

Az externalId a létrehozáskor rögzül, és ezen a végponton nem módosítható: ha elküldöd, a rendszer figyelmen kívül hagyja. Egy ügyfél külső azonosítója tehát állandó a kulcs névterében.

Az update szemantikája:

  • A megadott mezők felülírják a korábbi értéket; a kihagyott mezők változatlanok maradnak.
  • A customFields összefésül (merge): csak a megadott kulcsok módosulnak, a többi egyedi mező megmarad.
  • Mező ürítése üres stringgel. Az opcionális szöveges mezők (email, phone, company, taxNumber, notes, siteContactName, siteContactPhone, siteContactEmail) üres stringje ("") törli a mezőt. A name kötelező mező, nem üríthető (""400 INVALID_REQUEST_BODY). A null érték egyik mezőn sem elfogadott (400) — törléshez üres stringet küldj.
  • Az address részlegesen frissül: ha csak fullText-et küldesz, a strukturált mezők (zip / city / street) törlődnek (átváltás szabad szöveges címre), és fordítva. A country ilyenkor megőrződik (a korábbi értékről öröklődik, ha nem küldesz újat). Ha a cím érdemi része (zip / city / street / fullText) mind üres, az egész cím törlődik (a country-val együtt). A csak-fullText frissítésre is lefut a szabad szöveges cím feldolgozása: sikeres strukturáláskor a válasz már a kinyert mezőket adja (parsed_from_fulltext), warning nélkül.
Terminál
curl -X PATCH https://api.okosmunkalap.hu/v1/customers/abc123 \
-H "Authorization: Bearer omk_live_a1b2c3d..." \
-H "Content-Type: application/json" \
-d '{ "phone": "+36 70 987 6543", "isVip": true }'

Válasz: a módosított ügyfél a data mezőben.


Új munkalap létrehozása. A munkalap egy ügyfélhez kötődik, amelyet háromféleképpen lehet megadni (lásd a customer mezőt). Jogosultság: worksheets:create (a createIfMissing ág esetén emellett customers:create is).

Kéréstörzs:

Mező Típus Kötelező Megkötés
customer objektum igen ügyfél referencia, lásd lent
externalSystem string nem a lookupExternalId / createIfMissing cél-névtere, ha a kulcsnak több van; lásd Cél-névtér
title string nem megnevezés, max. 200
notes string nem publikus megjegyzés (pl. bejelentett hiba), max. 2000
internalNotes string nem belső megjegyzés, max. 2000
category string nem kategória, max. 100
siteContactName string nem bejelentő / helyszíni kapcsolattartó neve, max. 100
siteContactPhone string nem bejelentő / helyszíni kapcsolattartó telefonja, max. 30
customFields objektum nem { "mezőId": "érték" }
status enum nem draft (alapértelmezés) vagy in_progress
scheduledDate string nem ISO 8601
workAddress objektum nem munkavégzési cím, lásd Cím
items tömb nem tételek, lásd Munkalap tétel
assignments tömb nem kollégához rendelés, max. 20; team:read jogosultságot is igényel, lásd Hozzárendelés kollégákhoz
worksheetMode enum nem field (alapértelmezés) vagy service, lásd Szerviz munkalap
isSurvey boolean nem felmérés-e (alapértelmezés false), lásd Szerviz munkalap
devices tömb nem a javításra átvett eszközök, csak service módban
intakeCondition objektum nem átvételi dokumentáció, csak service módban
serviceLocation objektum nem a javítás műhelye, csak service módban
serviceLocationType enum nem site vagy customerAddress, csak service módban

A customer mező három alakja:

Alak Viselkedés
{ "id": "abc123" } meglévő ügyfélre hivatkozik a belső azonosítóval
{ "lookupExternalId": "CUST-9001" } a külső azonosítóval keres; ha nincs találat, 404; ha az érték több élő ügyfélre illeszkedik (duplikált), 409 (EXTERNAL_ID_AMBIGUOUS)
{ "lookupExternalId": "CUST-9001", "createIfMissing": { ... } } match-or-create: ha van találat, arra; ha nincs, új ügyfelet hoz létre a createIfMissing adataiból; ha az érték duplikált (több élő ügyfélre illeszkedik), 409 (EXTERNAL_ID_AMBIGUOUS) és nem hoz létre új ügyfelet

A createIfMissing objektum ugyanaz, mint a POST /v1/customers kéréstörzse, de externalId nélkül: azt a lookupExternalId és a kulcs névtere adja.

A lookupExternalId (és az esetleges létrehozás) névterét a kérés externalSystem mezője adja, vagy — ha kihagyod — a kulcs elsődleges névtere. Egynél több névteres kulcson, elsődleges és explicit externalSystem nélkül a hívás 400 (EXTERNAL_SYSTEM_AMBIGUOUS); tiltott névtér 403 (EXTERNAL_NAMESPACE_FORBIDDEN). A { "id": "..." } alakra ez nem vonatkozik (az közvetlenül a belső azonosítóra hivatkozik). Lásd Cél-névtér.

A siteContactName és siteContactPhone a munkalaphoz tartozik (a bejelentő vagy helyszíni kapcsolattartó). Ez független az ügyféltörzstől: nem módosítja az ügyfél adatait, és nem hoz létre ügyfelet.

A workAddress kizárólag a munkalap munkavégzési helyszíne. A munkalap számlázási címe automatikusan az ügyfél törzsadataiból áll össze („Megegyezik az ügyfél adataival“ snapshot: az ügyfél címe, cégneve, adószáma, email-je, telefonja), és az ügyfél adatainak későbbi módosításakor is frissül. Így a workAddress megadása nem befolyásolja a számlázási adatokat sem a felületen, sem a PDF-en, sem a számla és díjbekérő kiállításakor.

A bizonylat típusát két független mező adja: a worksheetMode (hol végzik a munkát) és az isSurvey (mi a dokumentum jellege). A négy kombinációnak külön sorszám-tartománya van, ugyanaz, mint a felületen:

worksheetMode: "field" worksheetMode: "service"
isSurvey: false ML (munkalap) SZ (szerviz munkalap)
isSurvey: true FE (felmérés) SZF (szerviz felmérés)

Szerviz módban a következő mezők adhatók meg. Kiszállásos (field) munkalapon mindegyik 400-at ad, mert a szerviz folyamat részei.

devices — a javításra átvett eszközök (max. 20). Elemenként: type (kötelező, max. 100), brand, model, serialNumber, accessories (max. 500), storageLocation (a fizikai tárolóhely a műhelyen belül, pl. „A-23 polc“; ez nem a telephely). Az eszközök bekerülnek a fiók eszköz-nyilvántartásába is, így a gép szerviz-előzménye a következő alkalommal előjön.

intakeCondition — a hibafelvétel: customerReportedIssue (az ügyfél által jelzett hiba; ha megadod a blokkot, kötelező) és notes (megjegyzés az eszköz állapotáról). Legalább egy type-pal rögzített eszközzel együtt ez a feltétele annak, hogy az átvételi jegyzőkönyv PDF-je generálható legyen — de csak műhelyes javításnál (serviceLocationType: "site"). Ügyfélcímes javításnál nincs eszközátvétel, ezért jegyzőkönyv sem készül, és a záró bizonylat teljesítési igazolás, nem kiadási bizonylat.

serviceLocation és serviceLocationType — hol javítják a gépet:

Alak Viselkedés
"serviceLocation": { "id": "loc_abc" } a megadott telephely; az azonosítót a GET /v1/service-locations adja
"serviceLocation": { "name": "Sopron Műhely" } telephely név alapján; kis-nagybetűtől és ékezettől függetlenül, magyar toldalékot elviselve. Nem egyértelmű névnél 409 (SERVICE_LOCATION_AMBIGUOUS), ismeretlennél 404 (SERVICE_LOCATION_NOT_FOUND), mindkettő a választható telephelyek nevével
"serviceLocationType": "customerAddress" a javítás az ügyfélnél történik (kiszállásos szerviz); a helyszín a workAddress, illetve az ügyfél címe
egyik sincs megadva a fiók alapértelmezett műhelye (utoljára használt, egyébként az első aktív telephely); telephely nélküli fióknál a cég címe

A serviceLocation és a serviceLocationType: "customerAddress" együtt nem adható meg (400), és műhelyes javításnál a workAddress sem: műhelybe átvett gépnél a munkavégzés helye maga a műhely, a küldött cím némán elveszne. Kiszállásos javításhoz a serviceLocationType: "customerAddress" a helyes alak, a címet ilyenkor a workAddress adja.

Miért fontos: műhelyes javításnál a műhely neve és címe kerül a munkalap PDF-jére, az ügyfélnek küldött email „Javítás helyszíne“ blokkjába (útvonaltervező gombbal), az átvételi jegyzőkönyvre és a számla megjegyzésébe. Ügyfélcímes javításnál ugyanezeken a helyeken az ügyfél címe jelenik meg, és a munkalapon kiszállási díj is felvihető.

Példa szerviz munkalapra:

Terminál
curl -X POST https://api.okosmunkalap.hu/v1/worksheets \
-H "Authorization: Bearer omk_live_a1b2c3d..." \
-H "Content-Type: application/json" \
-d '{
"customer": { "id": "abc123" },
"worksheetMode": "service",
"title": "Jura F50 javítás",
"serviceLocation": { "name": "Sopron Műhely" },
"devices": [
{ "type": "Automata kávégép", "brand": "Jura", "model": "F50", "serialNumber": "SN-1234", "storageLocation": "A-23 polc" }
],
"intakeCondition": {
"customerReportedIssue": "Nem darál",
"notes": "A víztartály karcos, a csepptálca hiányzik."
}
}'

A szerviz bizonylat az „Átvéve“ státuszban indul (a status mezőben a fiók szerviz státusz-láncának első eleme, l. GET /v1/worksheet-statuses), tehát a status bemenet szerviz módban nem érvényesül.

Terminál
curl -X POST https://api.okosmunkalap.hu/v1/worksheets \
-H "Authorization: Bearer omk_live_a1b2c3d..." \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 2a9f4b1c-..." \
-d '{
"customer": {
"lookupExternalId": "CUST-9001",
"createIfMissing": { "name": "Példa Kft.", "phone": "+36 30 123 4567" }
},
"title": "Riasztó hibajavítás",
"category": "Hibaelhárítás",
"notes": "A bejelentő szerint a központi panel nem reagál.",
"siteContactName": "Kovács Anna",
"siteContactPhone": "+36 70 222 3344",
"scheduledDate": "2026-06-16T09:00:00Z",
"items": [
{ "description": "Kiszállás", "type": "travel", "unitPrice": 8000, "vatRate": 27 },
{ "description": "Munkadíj", "type": "labor", "quantity": 1.5, "unit": "óra", "unitPrice": 12000 }
]
}'

Válasz (201):

{
"data": {
"id": "ws_abc123",
"worksheetNumber": "ML-2026-0042",
"status": "draft",
"customerId": "abc123",
"customerName": "Példa Kft.",
"title": "Riasztó hibajavítás",
"category": "Hibaelhárítás",
"siteContactName": "Kovács Anna",
"siteContactPhone": "+36 70 222 3344",
"scheduledDate": { "_seconds": 1781600400, "_nanoseconds": 0 },
"subtotal": 26000,
"vatAmount": 5528,
"total": 26000,
"items": [
{ "id": "itm_1", "type": "travel", "description": "Kiszállás", "quantity": 1, "unit": "db", "unitPrice": 8000, "totalPrice": 8000, "vatRate": 27 },
{ "id": "itm_2", "type": "labor", "description": "Munkadíj", "quantity": 1.5, "unit": "óra", "unitPrice": 12000, "totalPrice": 18000, "vatRate": 27 }
],
"customerCreated": false,
"createdAt": { "_seconds": 1781514000, "_nanoseconds": 0 },
"url": "https://app.okosmunkalap.hu/worksheets/ws_abc123"
}
}

A worksheetNumber az emberi olvasásra szánt munkalapszám (pl. ML-2026-0042), a url az alkalmazásban megnyitó hivatkozás. A customerCreated jelzi, hogy a hívás létrehozott-e új ügyfelet (true), vagy meglévőre hivatkozott (false). Ez a mező csak a létrehozás válaszában szerepel.

A példa egy frissen létrehozott (draft) munkalapot mutat. A válasz a kitöltöttségtől függően további mezőket is tartalmazhat: customFields ({ "mezőId": "érték" }, csak a munkalap saját egyedi mezői, ha ki vannak töltve — az ügyfél egyedi mezői nem jelennek meg itt) és completedAt (befejezés időpontja Firestore időbélyegként, ha a munkalap már lezárult). A munkalap items tömbjének minden eleme a Munkalap tétel szakaszban felsorolt mezőket adja vissza (a tétel belső készlet- és árazási mezői nem jelennek meg).

Ha a createIfMissing ág hoz létre ügyfelet, és az ügyfél-létrehozás figyelmeztetést ad (pl. ADDRESS_UNSTRUCTURED, mert a szabad szöveges cím feldolgozása nem járt sikerrel), a POST /v1/worksheets válasza is tartalmazza a top-level warnings tömböt — ugyanabban az alakban, mint a POST /v1/customers. Ha az új ügyfélnek számlázható címe kell, adj strukturált címet (zip + city).

Az összegek értelmezése: mivel a tételek unitPrice mezője bruttó egységár, a subtotal (a tételek bruttó összege) és a total (bruttó végösszeg) kedvezmény nélkül megegyezik. A vatAmount a bruttó összegben foglalt ÁFA (a példában a 26000 Ft bruttóban foglalt 27%-os ÁFA 5528 Ft).

A notes, internalNotes és workAddress mezők csak írhatók: a kérésben megadhatók, de a munkalap válaszában (és a webhook data mezőjében) nem jelennek meg.

Szerviz munkalap válaszában a helyszín is szerepel: a serviceLocationType (site vagy customerAddress) mindig, a serviceLocation objektum (id, name, code) pedig akkor, ha a javítás műhelyben történik. Kiszállásos munkalapon ezek a mezők nem jelennek meg.


Munkalapok szűrt listája kurzoros lapozással. Jogosultság: worksheets:read.

Query paraméter Leírás
status szűrés státuszra (lásd Munkalap státuszok)
customerId szűrés ügyfél belső azonosítóra
customerExternalId szűrés ügyfél külső azonosítóra (a kulcs névterében)
externalSystem opcionális: a customerExternalId keresett névtere, ha a kulcsnak több van; lásd Cél-névtér
scheduledDateFrom ütemezett dátum alsó határa, bezárólag (ISO 8601)
scheduledDateTo ütemezett dátum felső határa, bezárólag (ISO 8601). Csak dátumot (ÉÉÉÉ-HH-NN) megadva a teljes nap beleszámít (a nap végéig); idő-komponenssel a megadott pillanatig (<=)
limit oldalméret 1 és 100 között (alapértelmezés 20)
starting_after az előző oldal nextCursor értéke
Terminál
curl "https://api.okosmunkalap.hu/v1/worksheets?status=in_progress&limit=20" \
-H "Authorization: Bearer omk_live_a1b2c3d..."

Válasz:

{
"data": [
{ "id": "ws_abc123", "worksheetNumber": "ML-2026-0042", "status": "in_progress", "customerId": "abc123", "customerName": "Példa Kft.", "url": "https://app.okosmunkalap.hu/worksheets/ws_abc123" }
],
"pagination": { "hasMore": true, "limit": 20, "nextCursor": "eyJ..." }
}

A következő oldal lekérése a nextCursor átadásával:

Terminál
curl "https://api.okosmunkalap.hu/v1/worksheets?status=in_progress&limit=20&starting_after=eyJ..." \
-H "Authorization: Bearer omk_live_a1b2c3d..."

Lapozáskor tartsd változatlanul a szűrőket, különben 400 (INVALID_CURSOR). A customerExternalId szűrő külső rendszer névteret igényel: ha a kulcson nincs külső rendszer azonosító, a hívás 400 (EXTERNAL_SYSTEM_NOT_CONFIGURED). Ha van névtér, de a megadott külső azonosítóhoz nincs egyező ügyfél, a válasz üres lista. Több névteres kulcson a customerExternalId alapból minden névtérben keres; ha két különböző ügyfélre illeszkedne, a hívás 409 (EXTERNAL_ID_AMBIGUOUS) — szűkítsd az externalSystem paraméterrel (tiltott névtér 403 EXTERNAL_NAMESPACE_FORBIDDEN).

Rendezés: ha megadsz scheduledDateFrom vagy scheduledDateTo szűrőt, a lista scheduledDate szerint növekvő sorrendű; egyébként createdAt szerint csökkenő (a legújabb elöl). A lapozás stabil: azonos rendezőértékű munkalapoknál a belső azonosító a másodlagos rendezés.


Egy munkalap lekérdezése a belső azonosítója alapján. Jogosultság: worksheets:read.

Terminál
curl https://api.okosmunkalap.hu/v1/worksheets/ws_abc123 \
-H "Authorization: Bearer omk_live_a1b2c3d..."

Válasz: a munkalap a data mezőben (mint a létrehozásnál, customerCreated nélkül). Hatókörön kívüli vagy nem létező azonosító esetén 404 (WORKSHEET_NOT_FOUND).


Egy munkalap státuszának módosítása. Jogosultság: worksheets:write.

Kéréstörzs:

Mező Típus Kötelező Leírás
status enum igen az új státusz (lásd Munkalap státuszok)
completedAt string nem befejezés időpontja (ISO 8601)
confirmTerminalStatus boolean nem AI célú kulcsnál a végállapotú váltás megerősítése
Terminál
curl -X PATCH https://api.okosmunkalap.hu/v1/worksheets/ws_abc123/status \
-H "Authorization: Bearer omk_live_a1b2c3d..." \
-H "Content-Type: application/json" \
-d '{ "status": "in_progress" }'

Válasz: a frissített munkalap a data mezőben.

A státusz csak érvényes értékre állítható (a beépített státuszok vagy custom_ egyedi státusz). Érvénytelen érték 400 hibát ad. A státuszátmenetekre néhány szabály vonatkozik (érvénytelen átmenet 400 hibát ad):

  • A invoiced és a partially_invoiced (számlázott) munkalap csak cancelled, invoiced vagy partially_invoiced állapotba mehet tovább (számlázott munkalap nem nyitható vissza nem terminál állapotba).
  • A completed és a cancelled munkalap nem állítható vissza draft-ra.
  • Minden más átmenet megengedett.

AI célú kulcsok: ha a kulcs AI célú felhasználásra van jelölve, egy végállapotú státuszra (pl. completed, invoiced, cancelled, partially_invoiced) váltás emberi megerősítést igényel. Ilyenkor az első hívás 409 hibát ad CONFIRMATION_REQUIRED kóddal; a megerősítés után küldd újra a kérést "confirmTerminalStatus": true mezővel.


Egy munkalap hozzárendelése kollégákhoz, szerepkörrel. Jogosultság: worksheets:write. A userId értékeket a GET /v1/team-members végponttal oldd fel (ahhoz team:read kell).

A kéréstörzs a kívánt végállapotot írja le, nem hozzáad: a küldött lista lecseréli a munkalap addigi hozzárendeléseit. A hívás emiatt idempotens, megismételve ugyanazt az állapotot állítja be.

Kéréstörzs:

Mező Típus Kötelező Leírás
assignments tömb igen a kívánt hozzárendelések, max. 20; az üres tömb mindet törli. Lásd Hozzárendelés kollégákhoz
Terminál
curl -X POST https://api.okosmunkalap.hu/v1/worksheets/ws_abc123/assign \
-H "Authorization: Bearer omk_live_a1b2c3d..." \
-H "Content-Type: application/json" \
-d '{
"assignments": [
{ "userId": "u_9f21ab", "role": "lead" },
{ "userId": "u_44c0de", "role": "installer" }
]
}'

Válasz: a frissített munkalap a data mezőben, benne az assignments tömbbel.

Nem létező vagy a hatókörön kívüli munkalap 404 (WORKSHEET_NOT_FOUND). A hozzárendelések validálását (és a hibás esetek listáját) lásd a Hozzárendelés kollégákhoz szakaszban.


A fiók aktív csapattagjainak listája, névsorban. A hozzárendelésekhez szükséges userId feloldására való: a munkalap kollégához rendelése azonosítót vár, a partner-rendszer viszont általában nevet ismer. Jogosultság: team:read.

Terminál
curl https://api.okosmunkalap.hu/v1/team-members \
-H "Authorization: Bearer omk_live_a1b2c3d..."

Válasz:

{
"data": [
{
"userId": "u_9f21ab",
"displayName": "Kovács Péter",
"email": "kovacs.peter@pelda.hu",
"role": "admin",
"phone": "+36 30 111 2233"
},
{
"userId": "u_44c0de",
"displayName": "Nagy Anna",
"email": "nagy.anna@pelda.hu",
"role": "member"
}
]
}
Mező Leírás
userId a csapattag azonosítója; ezt add meg a hozzárendelésekben
displayName megjelenített név
email email cím
role csapat-szerepkör: owner, admin vagy member (ez nem a munkalap szerepköre)
phone csapaton belüli telefonszám, ha meg van adva
photoUrl profilkép URL, ha van

Csak az aktív tagok jelennek meg: a meghívott, még nem csatlakozott és az eltávolított tagok nem. Csapat nélküli fióknál a válasz üres lista (nem hiba).

A jogosultság azért külön team:read (és nem a worksheets:read része), mert a végpont személyes adatot ad vissza. A válasz szándékosan szűk: a tagok belső adatai (bérköltség, aláírás-kép, raktár- és modul-jogosultságok) nem kerülnek ki az API-ra.


A fiók egyedi mező definícióinak lekérdezése. Az ügyfeleknél és munkalapoknál customFields néven megadható egyedi mezők kulcsait innen ismerheted meg. Jogosultság: customers:read vagy worksheets:read.

Terminál
curl https://api.okosmunkalap.hu/v1/custom-fields \
-H "Authorization: Bearer omk_live_a1b2c3d..."

Válasz:

{
"data": [
{ "id": "fld_x1", "label": "Ügyfél törzsszám", "type": "text", "appliesTo": "customer", "required": false },
{ "id": "fld_y2", "label": "Berendezés gyári szám", "type": "text", "appliesTo": "worksheet", "required": false },
{ "id": "fld_z3", "label": "CRM ügyfélszám", "type": "text", "appliesTo": "customer", "required": false, "externalSystemNamespace": "crm" }
]
}
Mező Leírás
id a mező azonosítója; ezt használd kulcsként a customFields objektumban
label a mező megjelenített neve
type text vagy number
appliesTo customer vagy worksheet
required kötelező-e az alkalmazás felületén
externalSystemNamespace csak ha jelen van: a mező egy külső rendszer azonosítóhoz van kötve, ez a névtér neve. Az ilyen mezőt ne a customFields-en töltsd — a külső azonosítót az externalId + externalSystem párral állítsd (a válaszban és a webhookban a mező az externalIds alatt jön vissza, nem a customFields-ben). Ha mégis mindkettőt küldöd eltérő értékkel, 400 (EXTERNAL_ID_FIELD_MISMATCH).

Egy ügyfél vagy munkalap egyedi mezőjét tehát így töltöd ki: "customFields": { "fld_x1": "12345" }.

A customFields értékek mindig stringek, a mező type-jától függetlenül. Egy number típusú mezőt is stringként küldj (pl. "12345", nem 12345), különben a válasz 400 INVALID_REQUEST_BODY.


A fiók munkalap-státusz definícióinak lekérdezése. A munkalap status mezőjében kapott értékekhez (beépített, pl. draft, és egyedi, pl. custom_alkatreszre_var) adja meg a megjelenített nevet és a definíciót, az egyedi mezők végpontjának mintájára. Jogosultság: worksheets:read.

Terminál
curl https://api.okosmunkalap.hu/v1/worksheet-statuses \
-H "Authorization: Bearer omk_live_a1b2c3d..."

Válasz:

{
"data": [
{ "value": "draft", "label": "Piszkozat", "mode": "field", "color": "gray", "builtIn": true },
{ "value": "custom_alkatreszre_var", "label": "Alkatrészre vár", "mode": "field", "color": "#e28136", "builtIn": false },
{ "value": "invoiced", "label": "Számlázva", "mode": "field", "color": "emerald", "builtIn": true, "isCompleted": true }
]
}
Mező Leírás
value a státusz értéke; pontosan ezt kapod a munkalap status mezőjében, és ezt küldheted a PATCH /v1/worksheets/{id}/status hívásban
label a felületen megjelenített név
mode field (kiszállásos munkalap) vagy service (szerviz munkalap)
color a státusz színe (app-paletta token, pl. emerald, vagy hex kód)
builtIn beépített státusz-e (az egyedieknél false)
isCompleted csak ha true: a státusz teljesített (kész) munkának számít a fiókban
systemManaged csak ha true: a státuszt rendszer-folyamat kezeli; API-ból ne állítsd

A lista a felületi sorrendet követi. A definíciók fiókonként eltérhetnek (a tulajdonos átnevezheti a beépítetteket és sajátokat vehet fel), ezért érdemes futásidőben lekérdezni, nem beégetni.


A fiók aktív telephelyeinek listája névsorban: ezek közül választható a szerviz munkalap javítási helyszíne. Jogosultság: worksheets:read.

Terminál
curl https://api.okosmunkalap.hu/v1/service-locations \
-H "Authorization: Bearer omk_live_a1b2c3d..."

Válasz:

{
"data": [
{
"id": "loc_9f21ab",
"name": "Győr Műhely",
"code": "GY",
"address": { "zip": "9022", "city": "Győr", "street": "Pálffy u. 9", "country": "Magyarország" },
"isDefaultForRepairs": false
},
{
"id": "loc_44c0de",
"name": "Sopron Műhely",
"address": { "zip": "9400", "city": "Sopron", "street": "Mátyás király u 5", "country": "Magyarország" },
"isDefaultForRepairs": true
}
]
}
Mező Leírás
id a telephely azonosítója; ezt add meg a munkalap serviceLocation mezőjében
name a telephely neve, ahogy a bizonylatokon megjelenik
code rövid kód, ha van megadva
address a telephely címe
isDefaultForRepairs erre a telephelyre kerül a szerviz munkalap, ha nem adsz meg helyszínt

Csak az aktív, telephely típusú helyszínek jelennek meg: a raktár, a jármű és a virtuális helyszín nem javítási helyszín. Telephely nélküli fióknál a válasz üres lista (nem hiba): ilyenkor a szerviz munkalapra a cég címe kerül.

Az isDefaultForRepairs a fiók legutóbb használt műhelyét követi, ezért idővel változhat. Ha egy integrációnak mindig ugyanaz a műhely kell, add meg expliciten a serviceLocation mezőt.

Tétel felvétele a tételtörzsbe (anyag, munkadíj, kiszállás). Jogosultság: materials:create. A készlet modul Pro csomagtól érhető el; alacsonyabb csomagon a válasz 403 MODULE_NOT_AVAILABLE.

A végpont match-or-create: előbb meglévő tételt keres, és csak akkor hoz létre újat, ha nincs találat. Így egy megismételt vagy félbeszakadt hívás nem duplikálja a törzset.

Találat HTTP matched
nincs, új tétel jött létre 201 false
van, a meglévő tétel jön vissza 200 true
Terminál
curl -X POST https://api.okosmunkalap.hu/v1/materials \
-H "Authorization: Bearer omk_live_a1b2c3d..." \
-H "Content-Type: application/json" \
-d '{
"name": "Sarokszelep 1/2\"",
"sku": "SZ-001",
"unit": "db",
"purchasePrice": 1270,
"vatRate": 27
}'

Válasz (201):

{
"data": {
"id": "mat_7c31de",
"name": "Sarokszelep 1/2\"",
"sku": "SZ-001",
"type": "material",
"unit": "db",
"unitPrice": 1588,
"netUnitPrice": 1250,
"purchasePrice": 1270,
"netPurchasePrice": 1000,
"vatRate": 27,
"matched": false,
"createdAt": { "_seconds": 1781600400, "_nanoseconds": 0 },
"url": "https://app.okosmunkalap.hu/materials/mat_7c31de"
}
}

Az illesztés két szabálya (azonos a felület CSV-importjával):

  1. azonos cikkszám (sku),
  2. cikkszám nélkül: azonos név + egység + típus.

A megbízható kulcs a cikkszám. A név-egyezés kis- és nagybetű-érzékeny, tehát cikkszám nélkül a Csavar és a csavar két külön tétel lesz. Ha a rendszeredben van cikkszám, mindig küldd.

Árazás. Az unitPrice (bruttó eladási ár) elhagyható. Ilyenkor a rendszer a fiók felár-beállításából számolja a purchasePrice-ból, ugyanazzal a logikával, amit a bevételezés használ a felületen. Kikapcsolt felárnál a beszerzési ár lesz az eladási is (nem nulla). Alanyi adómentes fióknál az effektív ÁFA-kulcs 0, akkor is, ha a kérésben más szerepel.

Készlet. A végpont soha nem állít nyitókészletet és nem hoz létre készlet-mozgást: az árlistából nincs valós készlet-információ, egy itt megadott mennyiség pedig valódi bevételezésnek látszana a készlet-riportokban. A bevételezés a felületen (Raktár Kraft) történik. A minimumStock nem nyitókészlet, hanem a riasztási küszöb. A raktár hozzárendelése automatikus: a tétel a fiók alapértelmezett raktárához kerül, és ha még nincs raktár, a rendszer létrehozza.

Mező Kötelező Leírás
name igen a tétel megnevezése (max 200 karakter)
sku nem cikkszám (max 100), az elsődleges illesztési kulcs
type nem material (alapértelmezés), labor, travel, other
unit nem mértékegység, alapértelmezés db
internalName nem belső elnevezés, az ügyfél nem látja
category, manufacturer, notes nem kategória, gyártó, megjegyzés
purchasePrice nem bruttó beszerzési egységár (Ft)
unitPrice nem bruttó eladási egységár (Ft); elhagyva a felárból számolódik
vatRate nem 0, 5, 18 vagy 27
minimumStock nem készlet-riasztási küszöb

Tömeges felvitel. A végpont egy hívásban egy tételt hoz létre. Több száz soros beszállítói árlistához a felület CSV-importja való (Beállítások → Cég adatai → Import), ami egy menetben 5000 sort visz.


A tételtörzs szűrt listája, legújabb elöl. Jogosultság: materials:read. A készlet modul Pro csomagtól érhető el; alacsonyabb csomagon a válasz 403 MODULE_NOT_AVAILABLE, az olvasásra is.

Terminál
curl "https://api.okosmunkalap.hu/v1/materials?type=material&limit=50" \
-H "Authorization: Bearer omk_live_..."
Query paraméter Leírás
sku pontos cikkszám-egyezés
type material, labor, travel vagy other
limit oldalméret, 1 és 100 között (alapértelmezés 20)
starting_after az előző oldal pagination.nextCursor értéke

A válasz data tömbje ugyanolyan tétel-objektumokat tartalmaz, mint a létrehozásé, mellette a szokásos pagination blokk.

A szűrők tudatosan szűkek. Cikkszám és típus: az előbbi a lookup-kulcs, az utóbbi a leggyakoribb leszűkítés. Szabad szöveges keresésre a végpont nem való (arra az AI-összekötő search_materials eszköze van, ami a keresőindexen fut, és a magyar összetett szavakat is kezeli).

A lista nem tartalmaz készletet. A tétel-rekord a törzs adata (név, ár, egység), a raktári mennyiség külön nyilvántartás. Azt a következő végpont adja.


Egy tétel lekérése azonosítóval. Jogosultság: materials:read. Ismeretlen azonosítóra 404 MATERIAL_NOT_FOUND.


Egy tétel aktuális készlete raktáranként és összesen. Jogosultság: materials:read.

Terminál
curl https://api.okosmunkalap.hu/v1/materials/mat_7c31de/stock \
-H "Authorization: Bearer omk_live_..."
{
"data": {
"materialId": "mat_7c31de",
"name": "Sarokszelep 1/2\"",
"sku": "SZ-001",
"unit": "db",
"totalStock": 8,
"minimumStock": 10,
"locations": [
{
"locationId": "loc_kozponti",
"locationName": "Központi raktár",
"currentStock": 5,
"minimumStock": 10,
"stockLevel": "low_stock",
"binLocation": "A-03-02"
},
{
"locationId": "loc_furgon",
"locationName": "Szerelő furgon",
"currentStock": 3,
"stockLevel": "ok"
}
],
"url": "https://app.okosmunkalap.hu/materials/mat_7c31de"
}
}

A totalStock a locations sorok összege, tehát a végösszeg és a bontás mindig ugyanabból a forrásból jön. A stockLevel a felülettel azonos küszöbökkel számol: out_of_stock, low_stock, ok vagy overstock.

Készlet nélküli tételnél (nem raktározott munkadíj vagy még be nem vételezett anyag) a válasz totalStock: 0 és üres locations lista, nem hiba. A válasz nincs lapozva: a raktárak száma csomag-szinten korlátos.


Új árajánlat létrehozása egy meglévő ügyfélre. Jogosultság: quotes:create.

Az ajánlat mindig draft státuszban jön létre, és a végpont nem küldi ki az ügyfélnek: a kiküldés, az elfogadás és az elutasítás üzleti esemény, ami a felületen (illetve az ügyfél publikus oldalán) történik. Megosztási link sem keletkezik, azt az első megosztás hozza létre.

Terminál
curl -X POST https://api.okosmunkalap.hu/v1/quotes \
-H "Authorization: Bearer omk_live_a1b2c3d..." \
-H "Content-Type: application/json" \
-d '{
"customerId": "abc123",
"title": "Fürdőszoba felújítás",
"items": [
{ "description": "Csempézés", "quantity": 10, "unit": "m2", "unitPrice": 12700, "vatRate": 27 }
],
"validUntil": "2026-09-15"
}'

Válasz (201):

{
"data": {
"id": "qt_9f21ab",
"quoteNumber": "AJ-2026-0001",
"status": "draft",
"customerId": "abc123",
"customerName": "Példa Kft.",
"title": "Fürdőszoba felújítás",
"items": [
{ "id": "it_1", "type": "other", "description": "Csempézés", "quantity": 10, "unit": "m2", "unitPrice": 12700, "totalPrice": 127000, "vatRate": 27 }
],
"subtotal": 127000,
"vatAmount": 27000,
"total": 127000,
"validUntil": { "_seconds": 1789344000, "_nanoseconds": 0 },
"createdAt": { "_seconds": 1781600400, "_nanoseconds": 0 },
"url": "https://app.okosmunkalap.hu/quotes/qt_9f21ab"
}
}
Mező Kötelező Leírás
customerId igen a meglévő ügyfél belső azonosítója
title igen az ajánlat címe (max 200 karakter)
items igen legalább egy tételsor (max 200), szerkezete a Munkalap tétel inputtal azonos
notes nem ügyfélnek látható megjegyzés (max 5000)
internalNotes nem belső megjegyzés, az ügyfél sosem látja (max 5000)
validUntil nem az érvényesség vége ISO 8601 dátumként; elhagyva a létrehozástól számított 30 nap

Az összegeket a szerver számolja a tételsorokból, ugyanazzal a kalkulátorral, amit a felület használ: végösszeget nem lehet küldeni. Mivel a tételek unitPrice mezője bruttó egységár, a subtotal (a tételek bruttó összege) és a total (bruttó végösszeg) kedvezmény nélkül megegyezik; a vatAmount a bruttóban foglalt ÁFA.

Havi keret. Az árajánlat minden csomagban elérhető, de a havi darabszám csomagfüggő: Ingyenes 3, Alap 20, Profi és Üzleti korlátlan. A keret betelte után a válasz 403 (QUOTE_LIMIT_EXCEEDED), a details.limit és a details.current mezőkkel. A keret a naptári hónap fordulóján nullázódik. Ugyanez a keret vonatkozik a felületen készített ajánlatokra is: a kettő ugyanabból a havi darabszámból fogy.

Amit a végpont szándékosan nem tud. Ügyfél-rekord nélküli érdeklődőre nem készít ajánlatot (új ügyfélhez előbb a POST /v1/customers), nem állít draft-tól eltérő státuszt, nem ad dokumentum-szintű kedvezményt, és nem generál megosztási linket. Ezek a felület műveletei.

external_system hatókörű kulcsnál a hivatkozott ügyfélnek a kulcs névterében kell lennie, különben a válasz 404 (CUSTOMER_NOT_FOUND).


Árajánlatok szűrt listája kurzoros lapozással, a legújabb elöl. Jogosultság: quotes:read.

Query paraméter Leírás
status szűrés a tárolt státusz-értékre (draft, sent, viewed, commented, accepted, rejected, expired, worksheet_generated, survey_generated, vagy custom_ előtagú egyedi státusz)
customerId szűrés ügyfél belső azonosítóra
limit oldalméret 1 és 100 között (alapértelmezés 20)
starting_after az előző oldal nextCursor értéke
Terminál
curl "https://api.okosmunkalap.hu/v1/quotes?status=sent&limit=20" \
-H "Authorization: Bearer omk_live_a1b2c3d..."

Válasz:

{
"data": [
{ "id": "qt_9f21ab", "quoteNumber": "AJ-2026-0001", "status": "sent", "customerId": "abc123", "customerName": "Példa Kft.", "total": 127000, "url": "https://app.okosmunkalap.hu/quotes/qt_9f21ab" }
],
"pagination": { "hasMore": true, "limit": 20, "nextCursor": "eyJ..." }
}

Lapozáskor tartsd változatlanul a szűrőket, különben 400 (INVALID_CURSOR). A lista a felületen készített ajánlatokat is tartalmazza, tehát megjelenhet rajta olyan is, amit az API nem tud létrehozni (kedvezményes, érdeklődős vagy szerviz módú ajánlat).

external_system hatókörű kulcsnál a customerId szűrő kötelező: az árajánlat nem hordoz külső rendszer szerinti besorolást, ezért a hatókör csak ügyfelenként tartható. Szűrő nélkül a válasz 400 (MISSING_REQUIRED_FIELD).


Egy árajánlat lekérdezése a belső azonosítója alapján. Jogosultság: quotes:read.

Terminál
curl https://api.okosmunkalap.hu/v1/quotes/qt_9f21ab \
-H "Authorization: Bearer omk_live_a1b2c3d..."

Válasz: az árajánlat a data mezőben, a létrehozáséval azonos szerkezetben. Hatókörön kívüli vagy nem létező azonosító esetén 404 (QUOTE_NOT_FOUND).

A notes és az internalNotes mezők csak írhatók: a kérésben megadhatók, de az árajánlat válaszában nem jelennek meg. A megosztási token, az ügyfél-üzenetek és a megtekintés-számláló belső adatok, ezek sem kerülnek a válaszba.