Changelog
Промените во оваа верзија на API-то, со датумот кога станале достапни на demo околината и датумот кога се распоредени на продукција.
| Промена | Demo | Продукција |
|---|---|---|
| Податоците за издавачот веќе не се твоја работа: што документот не го носи, го пополнуваме од твојата организација. ЕДБ-то, ДДВ бројот и адресата на продавачот (улица, град, поштенски код) се земаат од матичните податоци на организацијата на која припаѓа клучот, пред фактурата да замине кон УЈП. Значи cac:AccountingSupplierParty смее да носи само име — како во работниот пример — и фактурата сега стигнува до УЈП. ⛔ Дотогаш таков документ се примаше со 201 и потоа застануваше: прво на 250 со EARH-4004 и failedStep ConvertFormat, а кога тоа беше расчистено — на 250 со EARH-4001 и ШЕСТ наода, сите за продавачот (sellerTin, улица, поштенски код, град, групата seller и sellerVatNumber). Објавената спецификација цело време велеше дека издавачот е незадолжителен, што важеше само за приемот. ⚠️ Пополнуваме само ПРАЗНО: вредност што документот ја носи не ја газиме. Но матичните податоци на издавачот ги одредува регистарот на УЈП — името и адресата се усогласуваат со регистрираните пред поднесувањето, и тоа важеше и досега. Ако впишеш ЕДБ на издавач, тоа мора да е ЕДБ-то на твојата организација; туѓо и понатаму се одбива со EARH-2007 во истиот повик. ⛔ Со тоа EARH-4004 престанува да биде исход на отсутни податоци за издавачот: таа шифра останува за тело што не може да се прочита (на пример без ниту една cac:InvoiceLine). Ниту едно постоечко поле, статус или шифра не го менува значењето. | 13.09.2026 | датумот сè уште не е одлучен |
| ⛔ ПРОМЕНА НА ОДНЕСУВАЊЕТО ПРИ ОБРАБОТКА: примачот повеќе не мора да е заведен партнер однапред. Непознат примач се ЗАВЕДУВА од самата фактура — од името, ЕДБ-то и адресата што ги носи — и обработката продолжува кон УЈП. Истото важи и во другата насока: испраќачот на влезна фактура се заведува при прием, што е и редот во стварноста — влезна фактура пристигнува без твојот софтвер да има шифра за таа компанија. Дотогаш документ за незаведен примач завршуваше на 250 со EARH-4005, што беше вообичаениот исход на ПРВ обид кај секој нов интегратор. Отсега EARH-4005 (и EARH-5020 во validationErrors) останува само за случај кога заведувањето не е можно: ЕДБ во неисправен облик што приемот го пропуштил, или партнер што е избришан во организацијата — избришан запис не се враќа во живот автоматски. НОВА АДРЕСА GET partners: партнерите на организацијата, со edb, name, address, city, postalCode, country, email, origin и changedAt по ред. origin кажува од каде е записот — OutboundInvoice, InboundInvoice, Manual, Erp или Unknown за постар запис. changedSince (yyyy-MM-dd или цел временски печат) враќа само променетото, а nextFrom во одговорот е почетната точка за следниот повик, исто како кај листите на документи. Страничењето е page и pageSize, најмногу 500 — повеќе се одбива со EARH-3005. ⛔ Датумот се чита строго по ISO: 10.09.2026 се одбива со EARH-2020, не се толкува. Шифрарниците добиваат erpCodes по запис — шифрите од ТВОЈОТ софтвер што организацијата ги мапирала кон таа шифра на УЈП, празен список кога нема ниту една. Со тоа однапред се проверува дали твоја вредност ќе помине, најважно за типот на документот: 380 од UBL-от е ТВОЈА шифра, а не шифра на УЈП. Ново е и тоа што cbc:InvoiceTypeCode (кај CreditNote: cbc:CreditNoteTypeCode) и двата cac:Country/cbc:IdentificationCode конечно се читаат од UBL-от како твои ERP шифри и минуваат низ мапирањето на организацијата — дотогаш UBL патеката не го пополнуваше типот на документот воопшто, па кај организација во режим Block ниту еден документ од интеграцискиот API не можеше да се поднесе. Ниту едно постоечко поле, статус или шифра не го менува значењето. | 13.09.2026 | датумот сè уште не е одлучен |
| Двете места каде одговорот молчеше сега кажуваат зошто. НОВО ПОЛЕ failedStep кај GET outbound/{docUid}: името на чекорот што паднал — ConvertFormat, ResolvePartner, UjpEFaktura и така натаму — пополнето само кај документ во неуспех. ⛔ Тоа е она што ги разликува двете значења на EARH-4004: пад во ConvertFormat значи дека документот не може да се прочита како што е пратен, значи причината е во твоето тело, а пад во подоцнежен чекор е обично на наша страна. Дотогаш каталогот тврдеше дека причината е СЕКОГАШ кај нас и те праќаше на поддршка за твоја грешка. Читај го полето, но не гранкај автомат по него: списокот чекори може да добие нови членови. НОВА ШИФРА EARH-5020 во validationErrors: примачот не е заведен партнер во организацијата. Таа е единствената причина зад EARH-4005, а дотогаш validationErrors кај тој исход беше ПРАЗЕН, па причината се читаше само во веб екранот — автоматизиран сервис можеше да каже само „одбиено, најавете се и погледнете". ⚠️ Со тоа validationErrors повеќе не е врзан само за EARH-4001; секој запис и понатаму се чита по својот code. Шифрарниците добиваат validFrom и validTo по запис, и нов незадолжителен параметар asOf (yyyy-MM-dd) — GET codelists/tax-indicators?asOf=2026-02-18. ⛔ Тоа е потребно затоа што при поднесување важењето се суди спрема датумот на ФАКТУРАТА, не спрема денешниот: заостаната фактура може да падне на шифра што денес е важечка, а дотогаш немаше како да го провериш тоа однапред. Изостанат asOf значи денес, како досега; датум што не може да се прочита се одбива со EARH-2020. Ниту едно постоечко поле, статус или шифра не го менува значењето. | 12.09.2026 | датумот сè уште не е одлучен |
| ⛔ ПРОМЕНА НА ОДНЕСУВАЊЕТО ПРИ ПРИЕМ: документ чиј издавач не е твојата организација отсега се одбива веднаш. НОВА ШИФРА EARH-2007 (400): ЕДБ-то впишано во cac:AccountingSupplierParty не е организацијата на која припаѓа клучот. Дотогаш таков документ се примаше, добиваше docUid, живееше во системот и тргнуваше кон УЈП — каде беше одбиен, па причината се гледаше дури како статус 250 со EARH-4002, часови подоцна и на погрешно место. Отсега одбивањето е во истиот повик и ниту еден документ не се создава. ⛔ Отсутен издавач НЕ е грешка: полето и понатаму не е задолжително, испраќачот се разрешува од клучот, и примерокот во упатството не го носи. Се одбива само ЕДБ што е внесено и е ДРУГО. Обликот со и без префикс MK е ист обврзник — MK4030995155258 и 4030995155258 поминуваат подеднакво, значи не мораш да ја менуваш формата што ја носи твојата база. Ако праќаш за повеќе организации, за секоја употреби нејзин клуч. Ниту едно постоечко поле, статус или шифра не го менува значењето. | 12.09.2026 | датумот сè уште не е одлучен |
| Одговорите што досега излегуваа надвор од договорот добиваат шифра, а влезните документи конечно се читаат целосно. ⛔ НОВА ШИФРА EARH-2020 (400): параметар што не може да се прочита — недостасува задолжителен (на пример format кај преземањето фајл), датумот не е датум, или вредноста е надвор од дозволените. Дотогаш такво барање враќаше тело БЕЗ поле code, значи немаше по што да се гранка. Полето detail го именува параметарот. Со тоа и ?status=999 повеќе не минува тивко: порано враќаше 200 со празен список, што изгледаше исто како „нема такви документи", а сега е EARH-2020 што ги набројува дозволените статуси. Непредвидена грешка отсега секогаш е EARH-9000 со eventId, наместо поранешниот сиров облик (errorRef, errorCode, message). ⛔ POST outbound прима и text/xml, application/octet-stream и барање без Content-Type: досега само application/xml поминуваше, а сè друго враќаше 404 EARH-1009 „адресата не постои во ова издание" — порака што го праќаше интеграторот да ја бара грешката на погрешно место. Обликот на телото и понатаму го судат EARH-2001 и EARH-2002. GET inbound/{docUid}/file конечно враќа содржина за фактури преземени од УЈП — format=original беше објавен како секогаш достапен, а враќаше 404 EARH-3002 за секоја таква фактура. Статусите 140 (одобрен) и 150 (одбиен) сега се гледаат на влезен документ штом одлуката е запишана, заедно со rejectionReason кај одбиените; дотогаш документот стоеше на 120 без разлика на одлуката. receivedAt носи вистинско време — кај фактурите преземени од УЈП стоеше 0001-01-01T00:00:00. Историјата на излезен документ повеќе не го повторува 230 двапати и завршува со 270 кога документот е архивиран, исто како што кажува GET outbound/{docUid}. Сторнирањето сега навистина запира: POST outbound/{docUid}/cancel во состојба 210 или 220 ја прекинува обработката, а фактура што УЈП веќе ја прифатил се одбива со 409 EARH-3003 наместо да добие 260 што не одговара на стварноста. Ниту едно постоечко поле не го менува значењето. | 12.09.2026 | датумот сè уште не е одлучен |
| Одговорот ја носи и врската за QR кодот што УЈП ја вратил. Ново поле qrLink во блокот ujp — кај POST outbound и кај GET outbound/{docUid} — веднаш по euid, и ujpQrLink по ред во листата GET outbound. Тоа е точно врската што УЈП ја вратил при прифаќањето на фактурата, истата што ја втиснуваме во QR кодот на нашиот PDF. Ако фактурата ја печатиш во свој PDF, втисни ја неа како QR код. ⛔ Не ја составувај од euid: адресата е различна по околина и ја одредува УЈП. Празна е додека УЈП не ја прифатил фактурата, и останува празна кај одбиена. Со Prefer: wait истиот одговор ги носи и euid и qrLink. Ниту едно постоечко поле, шифра или статус не е изменето. | 11.09.2026 | датумот сè уште не е одлучен |
| Одговорот на POST outbound го носи UJP ID, а праќањето може да чека на исходот. Ново поле ujp во одговорот — euid е идентификаторот што УЈП го доделил на фактурата, state, code и message се неговиот одговор, checkedAt кога е последно проверено. Сите се празни додека УЈП не одговорил. Ново е и failureCode во истиот одговор. Незадолжителното заглавие Prefer: wait=N (N до 30 секунди) го задржува одговорот додека нашата обработка не заврши со поднесувањето кон УЈП — не додека УЈП не одлучи понатаму, и не додека не заврши архивирањето и доставата. Одговорот го носи заглавието Preference-Applied со вистински применетото чекање. Без Prefer одговорот доаѓа веднаш, со статус 210, како досега; ако чекањето истече пред исходот, состојбата се чита со GET outbound/{docUid}. Листата GET outbound добива ujpEuid по ред. ⛔ Документ чија обработка паднала ПРЕД поднесувањето кон УЈП отсега завршува на 250 со failureCode — дотогаш остануваше на 210 засекогаш и не се разликуваше од документ што уште се обработува. Ниту едно постоечко поле, шифра или статус не го менува значењето. | 11.09.2026 | датумот сè уште не е одлучен |
| GET outbound/{docUid}/file и GET inbound/{docUid}/file враќаат уредна грешка кога нешто не е во ред. ⛔ Дотогаш барање за формат што документот го нема враќаше 406 Not Acceptable со ПРАЗНО тело наместо 404 EARH-3002: адресата објавуваше само application/octet-stream, па одговорот со шифра — што е JSON — не можеше да се испорача. Значи повикувачот добиваше HTTP код што не кажува ништо за причината. Отсега обете адреси враќаат 404 со EARH-3001 (нема таков документ) или EARH-3002 (документот не пристигнал во тој облик), како што и досега пишуваше во описот. Ново е EARH-9003 (409): записот за фајлот постои и тврди дека содржината е зачувана, но неа ја нема — ниту локално ниту во облак. ⛔ Тоа НЕ е EARH-3002: таа шифра значи дека документот не пристигнал во тој облик, што е уредна состојба; оваа значи дека обликот постоел и содржината е загубена. Дотогаш тој случај излегуваше како сурова 500 со облик што не е дел од договорот (errorRef, errorCode, message) и без шифра по која да гранкаш. Сите останати податоци за таков документ — статус, износи, историја — и понатаму се читаат нормално. Ниту едно постоечко поле, шифра или статус не е изменето. | 02.09.2026 | датумот сè уште не е одлучен |
| Влезните фактури за тестирање се полнат со една команда. POST sandbox/seed создава серија влезни документи, по еден за секое сценарио, и одговорот кажува што претставува секој од нив — за тестот да тврди наместо да погодува. Истиот seed секогаш дава иста серија: исти износи, исти датуми, исти испраќачи, исти рокови. Изостанат seed значи 1, не случаен број — прв повик што не може да се повтори би ја промашил целата намена. reset ги брише фактурите што оваа команда ги создала претходно и ништо друго, па автоматско извршување може да почне од иста состојба секој пат; документ внесен преку sandbox/inbound останува недопрен. scenarios ја стеснува серијата; изостанато значи сите, а непознато име се одбива со EARH-2030 и одговорот ги набројува дозволените. ⛔ Најважни се трите сценарија што завршуваат со 409 EARH-3006 — deadlinePassed, alreadyAccepted, alreadyRejected. Тие состојби настануваат со текот на времето или со дејство што веќе се случило, значи не може да се создадат преку sandbox/inbound, и токму затоа софтвер што не ги сретнал во тестирање прв пат ги гледа во продукција. Останатите покриваат содржина (full, payloadOnly, pdfOnly, noContent), потврден прием (acknowledged), рок што истекува денес (deadlineToday), износи (zeroVat, creditNote, largeAmount) и филтри (secondSender, olderThanWeek, updatedRecently). Имињата се стабилни и може да се впишат во тест, но подобро е списокот да се чита од одговорот — тогаш тестот останува точен и кога ќе додадеме ново сценарио. ⛔ Не постои на продукција: таму адресата враќа EARH-1009. Ниту едно постоечко поле, шифра или статус не е изменето. | 02.09.2026 | датумот сè уште не е одлучен |
| Целата патека може да се помине на demo серверот, без ниту еден документ да замине кон УЈП. Ново: POST sandbox/inbound внесува влезен документ во твојата организација низ истиот пат на прием како вистински, па GET inbound, GET inbound/{docUid}/file и POST inbound/{docUid}/decision може да се проберат од крај до крај; единственото задолжително поле е documentNumber, а истиот euid го враќа постојниот документ наместо да создаде втор. Излезен документ поднесен овде застанува по составувањето и проверката на УЈП пораката и добива нов статус 225 — проверен, но не поднесен. Тоа НЕ е неуспех и не носи failureCode; документ што паднал на проверката и понатаму добива 250 со EARH-4001. Составената порака се презема со GET outbound/{docUid}/file?format=ujp-json. Одлука по влезен документ исто се запишува кај нас, но не се пријавува кон УЈП. ⛔ Ниту едно од ова не постои на продукција: таму POST sandbox/inbound враќа EARH-1009, а статусот 225 не настанува. Ново е и полето validationErrors кај GET outbound/{docUid}: кога failureCode е EARH-4001, тоа ги носи поединечните причини со шифри EARH-5001 до EARH-5012 — таа шифра кажува ШТО се случило, овие кажуваат КАДЕ. Гранкај по code на секој запис; полето path покажува кое поле да го погледнеш и НЕ е дел од договорот. Додадена е и шифрата EARH-2030 (400) за неупотребливо тело кон sandbox/inbound. Ниту едно постоечко поле, шифра или статус не е изменето. | 01.09.2026 | датумот сè уште не е одлучен |
| ⛔ ПРОМЕНА НА ОБЈАВЕНА ГРАНИЦА: сообраќајот се мери по клуч, а бројката повеќе не е рамна 300 за сите. Дотогаш границата се броеше по мрежна адреса, што значеше дека два клуча зад иста адреса делеа квота, а ист клуч од две адреси добиваше двојна — спротивно од она што е објавено во „Ограничувања и правила". Отсега партицијата е самиот клуч, а вредноста ја носи планот на организацијата: Стартер 60, Професионален 300, Enterprise без ограничување, Бесплатен без интеграциски пристап. Сопственикот на клучот може да ја спушти границата уште подолу за тој клуч; важи помалото од двете. Со тоа се појавуваат и ДВЕ НОВИ ШИФРИ, обете 403 и обете на СЕКОЈ повик, не по исцрпена квота: EARH-1010 планот на организацијата не носи интеграциски пристап, и EARH-1011 клучот е изгаснат од сопственикот. ⛔ Ниту една од двете не носи Retry-After — чекањето не ја менува состојбата, па повторување во јамка нема да успее. EARH-1006 (429) останува непроменето и понатаму го носи Retry-After. | 29.08.2026 | датумот сè уште не е одлучен |
| ⛔ ПРОМЕНА НА ВРЕДНОСТИ: статусните шифри се преномерираат. Отсега првата цифра ја кажува насоката, а последните две чекорот во животниот циклус: влезните документи носат 1xx, излезните 2xx. Излезните 10, 20, 30, 40, 50, 60, 70 стануваат 210, 220, 230, 240, 250, 260, 270; значењата остануваат непроменети. Влезните 110, 120, 140, 150 остануваат исти, а резервираната 160 се дели на 170 архивиран и 180 примен конечен документ од УЈП. Со тоа истиот чекор носи ист завршеток кај двете насоки (140 ↔ 240, 150 ↔ 250), а ниту една наша шифра повеќе не се совпаѓа со шифрарникот на УЈП, кој е двоцифрен. Ова е ЕДИНСТВЕНОТО отстапување од правилото дека постоечка вредност не го менува значењето, и е направено пред издавањето на првиот клуч за demo околината — токму за да не се плати подоцна. | 29.08.2026 | датумот сè уште не е одлучен |
| Одлуката по влезен документ се донесува преку API. POST inbound/{docUid}/decision прифаќа или одбива влезен документ. Одбивањето носи и код на причина од кодната листа reject-reasons и коментар; прифаќањето не носи ниту едно од двете. Одлуката се запишува пред да се пријави натаму, па успешен одговор значи дека е примена — дали УЈП веќе ја потврдил стои во полето confirmedByTaxAuthority. Прочитај го decisionDeadline пред да одлучуваш: по тој ден УЈП го прифаќа документот сам, и одлука пратена потоа се одбива. | 29.08.2026 | датумот сè уште не е одлучен |
| Влезните документи носат состојба и причина за одбивање. GET inbound и GET inbound/{docUid} враќаат status со нумеричка шифра (110 примен, 120 во обработка, 140 одобрен, 150 одбиен), а rejectionReason доаѓа со документ што е одбиен. Обете листи враќаат и nextFrom — почетна точка за следниот повик, за повлекување само на она што се сменило. Ниту едно постоечко поле не е изменето. | 28.08.2026 | датумот сè уште не е одлучен |
| Влезните документи го носат рокот за одлука. GET inbound и GET inbound/{docUid} враќаат decisionDeadline — денот до кој документот мора да биде одобрен или одбиен, кога таков рок постои. Вредноста е календарски датум, без час и без временска зона, и останува видлива и откако документот е одлучен. По истекот на тој ден УЈП го прифаќа документот сам. | 28.08.2026 | датумот сè уште не е одлучен |