X/ XNet API Developer guide
API v1 · Комплетен contract

XNet · HTTPS · JSON

API патоказ за програмери.

Практичен водич за сигурна интеграција со XNet: еден endpoint, предвидлив JSON договор и корелирани одговори за секое барање.

POST https://vps.xnet.mk:50443/api/commands

01 · Quickstart

Од идеја до прв успешен повик

Сите команди се испраќаат како UTF-8 JSON преку HTTPS. За секое барање креирајте нови идентификатори и краток рок на важност.

01

Подгответе клиент

Користете HTTPS клиент со JSON поддршка и разумен timeout. Заглавието Content-Type мора да биде application/json.

02

Создајте envelope

Генерирајте нов messageId, стабилен clientSessionId и conversation id. Започнете со turn 1.

03

Додадете credentials

Повеќето барања содржат username и password; заштитените операции ги проверуваат во Users кешот. Документираните исклучоци се без најава.

04

Поврзете го одговорот

Проверете HTTP статус, status и error. replyToMessageId секогаш треба да одговара на испратениот messageId.

!

Адреса на сервисот: Документацијата е на api.xnet.mk, а API повиците одат на vps.xnet.mk со задолжителната порта 50443. Користете ја целата адреса прикажана погоре; портата 443 моментално не е API endpoint.

i

HTTP endpoint-от се активира пред schema/cache иницијализацијата. /health може привремено да врати databaseReady: false; тогаш повторете ја операцијата откако кешот ќе се вчита.

02 · Contract

Еден envelope за секоја команда

Структурата е верзионирана и обезбедува следливост меѓу апликации, клиенти и разговори. Полето data секогаш е JSON object.

request-envelope.json
{
  "schemaVersion": 1,
  "messageId": "<new-uuid>",
  "authentication": {
    "username": "<username>",
    "password": "<password>"
  },
  "client": {
    "appId": "idiot.mk",
    "appVersion": "1.0.0",
    "clientSessionId": "<session-uuid>"
  },
  "conversation": {
    "id": "<conversation-uuid>",
    "turn": 1
  },
  "operation": "system.ping",
  "sentAtUtc": "<current-utc-time>",
  "expiresAtUtc": "<short-future-utc-time>",
  "data": {}
}
ПолеТипЗначење
schemaVersionintegerМора да биде 1.
messageIdUUIDНов, непразен идентификатор за секое барање.
authentication.username
authentication.password
stringЗадолжителни за заштитените операции, со документираните исклучоци за лиценца и XMan зачувување фирма.
clientobjectИдентитет на апликацијата, верзија и непразен session UUID.
conversationobjectНепразен id и turn поголем од 0.
operationstringИмето на серверската функционалност.
expiresAtUtcISO 8601 / nullАко е зададено, мора да биде во иднина.
dataobjectПараметри за операцијата; никогаш JSON запишан како string.

03 · Operations

Достапни функционалности

Еден contract ги покрива автентикацијата, Finmath и root операциите, Обврски, јавниот feed, објавувањето, гласањето, коментарите, пријавите и администраторската модерација.

READ

system.ping

Проверува дали сервисот прифаќа и обработува валидни команди.

200
data / response
// request.data
{}

// response.data
{ "text": "pong" }
WRITE

user.register

Креира корисник само во локалната kesh.users база и целосно го освежува Users кешот.

201
response.data
{
  "userId": 123,
  "username": "developer",
  "email": "dev@example.com",
  "confirmed": true,
  "emailDelivery": "not-required"
}
КатегоријаoperationauthenticationНамена
Authuser.confirm-email
user.resend-confirmation
credentials presentЗадржани за компатибилност; email потврдата привремено не е потребна.
Authuser.login
user.me
user.update
user.profile-picture.update
verified credentialsПроверка на username/password, читање и промена на сопствениот профил без токени.
Finmathcatalog.country-city
company.create
company.search
company.connection.request
finmath.company.register
finmath.company.delete-or-archive
finmath.bookkeeping.register
finmath.bookkeeping.clients
verified credentialsКаталог, регистрација, реални фирма-до-фирма врски и интерни фирми од базата на книговодството, без директна клиентска MySQL конекција.
Обврскиobvrski.list
obvrski.save
obvrski.delete
obvrski.reorder
obvrski.step.save
obvrski.step.delete
verified credentialsЧитање, промена и зачуван редослед само на обврските и нивните чекори за најавениот корисник во фиксната база 09_obvrski. Клиентот користи appId: "obvrski" и не избира база.
Feedpost.list
post.get
post.comment.list
credentials presentЈавни одобрени објави и коментари.
Contentpost.create
post.my
post.vote
post.comment.create
post.report
verified credentialsОбјавување, сопствена историја и интеракции.
Adminadmin.post.pending
admin.post.moderate
admin.report.list
admin.report.resolve
verified credentials + adminОдобрување објави и обработка на пријави. root-manager ја користи истата најава од 00_x.usrs.

04 · user.register

Регистрација и автентикација

Заштитените операции содржат username и password; `coffeemath.license.request` и точното `mk.xman` зачувување фирма се документирани исклучоци. Нема access/refresh токени или серверски сесии; заштитените операции ги проверуваат credentials преку Users кешот, освен admin барањата од root-manager кои се проверуваат во 00_x.usrs.

user.confirm-email

Привремено не е потребно. Новите и постојните сметки серверот ги смета за потврдени.

user.login

Испрати username и password во authentication; успешниот одговор нема токени.

user.me

Ги проверува credentials повторно и враќа безбеден профил и isAdmin.

user.update

Ги менува сопствените профилни податоци само во kesh.users и го освежува Users кешот.

user.profile-picture.update

Ја менува само профилната слика. null или празен string ја отстранува; максималната должина е 700.000 знаци.

CORS · rate limit

Дозволени origins се idiot.mk, www.idiot.mk и api.xnet.mk. Ограничувањето е 120 барања во минута по IP, а request body е најмногу 1 MB.

ПолеУсловВалидација
usernameЗадолжително3–45 знаци, без празни места.
passwordЗадолжително8–256 знаци. Се испраќа само преку HTTPS.
emailЗадолжителноВалидна адреса, најмногу 60 знаци.
name, surnameОпционалноНајмногу 45 знаци по поле.
pid, address, city, country, phoneОпционалноНајмногу 45 знаци по поле.
languageIdОпционалноЦел број од 1 до 127; стандардно 1.
birthdayОпционалноYYYY-MM-DD; не смее да биде во иднина.
primeRegistrantОпционалноНајмногу 45 знаци.
profilePictureОпционалноString до 700.000 знаци; избегнувајте го кога не е неопходно.
✓

Безбедност: Лозинката не се враќа во одговорот и се зачувува како PBKDF2-SHA256 hash. Не логирајте password или profilePicture во клиентската апликација.

05 · Finmath 3

Најава и регистрација на фирма за Finmath 3

Клиентот користи appId finmath-3. По најавата, response.data.finmath го содржи корисничкиот профил и сите достапни фирми; клиентот не се поврзува директно на MySQL.

user.login

По проверка на credentials враќа finmath.connections за избор на фирма или книговодство, без токени.

catalog.country-city

Со проверени username/password ги враќа активните држави и градови на mk, en или sq.

company.create

Креира реална фирма за најавениот сопственик. Задолжителниот requestId го прави повторувањето по timeout идемпотентно.

company.search

Пребарува од два знака и враќа само безбедни јавни полиња и стабилен companyGuid, без база или credentials.

company.connection.request

Креира само pending барање со role=999; не доделува активен или администраторски пристап.

finmath.company.register

Бара одобрена книговодствена конекција, запишува директно во Hetz базата без stored procedures и го освежува локалниот kesh.

finmath.company.delete-or-archive

Проверува само zz_NNNNNNN_* табели. Непразна табела ја архивира фирмата; ако сите се празни, во deleted_companies LIKE 00_x.log_root ги зачувува целата фирма и сите user-connections како JSON, па ги брише само тие централни редови.

finmath.bookkeeping.register

Креира книговодство со нова база со следниот слободен 04_ реден број и одобрена улога FinmathAccounter.

finmath.bookkeeping.clients

Ги спојува активните реални фирми од company_relations со валидните интерни фирми од my_settings и активните директни интерни конекции за истата книговодствена база. Позитивен ID и непразен краток назив се задолжителни; дозволен е и назив од еден знак, а zz_ работни табели не се услов.

root.data

Сите legacy Data_In повици од shared root одат во Listener. Нема повик или fallback кон 00.get_data; Listener проверува пристап и ја рутира конкретната операција. Операцијата 12 (ReadEmploeyees) ги враќа корисниците и работните податоци само за достапните фирми, вклучувајќи ги интерните фирми на одобреното книговодство, без лозинки. Операцијата 333 (Finmath_Salary_Status_List) параметризирано ги чита payroll статусите од сите директно или книговодствено достапни фирмени бази. Listener при старт ги вчитува 00_x шаблонските табели во меморија. При MySQL 1146 за побарана фирмена табела, ја обновува само ако основниот назив е во меморискиот каталог. Истиот repair-сервис ги покрива и Magmath 6 статистиките за clients и articles.

finmath.company.register / data
{
  "bookkeepingConnectionId": 321,
  "password": "user-password",
  "shortName": "firma_2026",
  "wholeName": "Фирма ДООЕЛ Скопје",
  "address": "Партизанска",
  "number": "10",
  "city": "Скопје",
  "country": "Македонија",
  "taxNumber": "MK1234567",
  "pid": "1234567",
  "taxObligated": true,
  "planType": 1,
  "accountantPlan": 1,
  "kontenPlanSource": 1,
  "sourceType": 1
}

06 · Reference

Целосна практична референца

Табелите подолу се договорот што треба да го следи клиентот: точен appId, дали credentials само мора да постојат или и се проверуваат, обликот на data и главниот резултат. Сите data вредности се JSON objects.

Поддржани клиенти и избор на база

client.appIdСерверска политика за база
idiot.mkidiot — фиксна база
finmath-3Базата се определува од одобрената избрана фирма.
finmath-3-internalСе користи базата на одобреното избрано книговодство.
magmat-b, inmath-2Базата се определува од одобрената избрана фирма.
obvrski09_obvrski — фиксна база; клиентот не испраќа име на база.
root-manager00_x — Root Manager credentials, дозволени само за admin.*.
domIOЗаеднички XNet идентитети и активни domio.* операции за домови, членови, катови, простории и уреди. Физичкиот provider сè уште не е поврзан.
!

Секој друг appId се одбива со unsupported-client-app. Credentials се задолжителни во секој envelope; ознаката „присутни“ значи дека за таа јавна операција не се проверуваат, а „проверени“ значи дека username/password мора да одговараат на корисник од вчитаниот Users кеш. Само root-manager admin барањата се проверуваат во 00_x.usrs.

Систем, корисници и каталог

operationauthenticationdataГлавен response.data
system.pingприсутни{}{ text: "pong", apiVersion: 1 }
user.registerприсутни и исти со data{ name?, surname?, username, password, pid?, address?, city?, country?, phone?, email, languageId?, birthday?, primeRegistrant?, profilePicture? }{ userId, username, email, confirmed, emailDelivery } · HTTP 201
user.confirm-emailприсутни{ identity, code }{ confirmed, alreadyConfirmed }
user.resend-confirmationприсутни{ identity }{ accepted: true }
user.login / user.meпроверени{}{ userId, username, ..., finmath?: { connections[] } }; за Finmath ги содржи и pending конекциите.
user.meпроверени{}Безбеден кориснички профил и isAdmin, без лозинка или токени.
user.updateпроверени{ name?, surname?, username, pid?, address?, city?, country?, phone?, email, languageId, birthday? }Целосен освежен профил со profilePicture. Ако username се менува, овој повик користи старо, а следниот ново username.
user.profile-picture.updateпроверени{ profilePicture: string|null }Целосен освежен профил; null или празен string ја отстранува сликата.
catalog.country-cityпроверени за Finmath; само присутни за другите клиенти{ language?: "mk|en|sq", countryId?: number|null, activeOnly?: bool }{ language, countries[], cities[] }

Finmath 3

operationdataГлавен response.data
finmath.company.register{ bookkeepingConnectionId, password, shortName, wholeName, address, number, city, country, taxNumber, pid, taxObligated, planType, accountantPlan, kontenPlanSource, sourceType? }Порака, резултат од креирањето и целосно освежен finmath профил · HTTP 201.
company.create{ requestId, shortName, wholeName?, address?, number?, city?, country?, taxNumber?, pid?, taxObligated, industry }Реална фирма и одобрена owner конекција · HTTP 201. Типови 1–6; не е исто со finmath.company.register.
company.search{ term: string[2..100] }Јавен резултат со query, containsResults[], similarResults[] и стабилен companyGuid.
company.connection.request{ companyGuid }{ requestStatus: "pending|already-connected", connectionId, refreshStatus }.
finmath.company.delete-or-archive{ companyConnectionId }action е archived ако некоја zz_NNNNNNN_* табела има записи; инаку deleted, со освежен finmath профил.
finmath.bookkeeping.register{ password, shortName, wholeName, address, number, city?, cityId?, country?, countryId?, taxNumber, pid, taxObligated, planType }Порака, креирана книговодствена фирма/база и освежен finmath профил · HTTP 201.
finmath.bookkeeping.clients{ bookkeepingConnectionId }{ bookkeepingCompanyId, bookkeepingCompanyGuid, connections[], bookkeepingDatabase, bookkeepingServerAddress }
root.data{ request: Data_In_object }root-компатибилен JSON резултат. Неподдржан Operation_Type се одбива; нема fallback кон 00.get_data.

Поддржани root.data Operation_Type вредности

Operation_TypeНаменаOperation_TypeНамена
2ReadData3Insert
4Update5Delete
11ReadDocuments12ReadEmploeyees
15RegisterFinancialWarrant18RegisterBankStatement
25ArticleHistoryByYear41CreateTable
51UpdateUser87OwnerReport
92RegisterForexCalculation103CountryCityStructure
110ArticleHistoryDetails124ProfitReport
130ClientSubjectsRead131ClientSubjectSave
140AlmanacCreateSchool310FeedbackCreateTicket
311FeedbackListTickets312FeedbackGetTicket
313FeedbackAddMessage333FinmathSalaryStatusList
i

root.data е compatibility рута за постојната shared root библиотека, не општ SQL endpoint. Самата бројка Operation_Type не е доволна: data.request мора да го следи точниот Data_In модел за таа операција. Непренесените операции се одбиваат експлицитно.

Almanac · училишен веб-клиент и дозволени операции

Almanac · Google најава, поврзување профили и серверска проверка — потребна е Google Cloud конфигурација.

Обврски · appId: "obvrski"

operationdataГлавен response.data
obvrski.list{}Низа од сопствените обврски, секоја со steps[].
obvrski.save{ id: uuid, title, description?, dueDate: "yyyy-MM-dd", priority: 0|1|2, isCompleted, sortOrder, createdAt? }Креираната или изменетата обврска.
obvrski.delete{ id: uuid }{ id, deleted: true }
obvrski.reorder{ orderedIds: [uuid, ...] }{ reordered: true, count }
obvrski.step.save{ id: uuid, obligationId: uuid, title, isCompleted, sortOrder, createdAt? }Креираниот или изменетиот чекор.
obvrski.step.delete{ id: uuid, obligationId: uuid }{ id, obligationId, deleted: true }

Feed, содржина и администрација

Кај анонимна објава серверот го зачувува вистинскиот автор, но post.list и post.get враќаат само author { displayName: "Анонимен корисник", username: null, profilePicture: null }. Само admin.post.pending го враќа вистинскиот author со userId.

operationauthenticationdataГлавен response.data
post.listприсутни{ limit?: 1..50, beforeId?: number|null }{ items, count }
post.getприсутни{ postId }Одобрена јавна објава.
post.comment.listприсутни{ postId }{ items, count }
post.createпроверени{ title, description, location?, occurredAtUtc?, mediaUrl?, isAnonymous?: boolean=false }Нова pending објава · HTTP 201.
post.myпроверени{ limit?: 1..50, beforeId?: number|null }{ items: [{ isAnonymous, isOwner: true, ... }], count }
post.voteпроверени{ postId, selected: bool }{ selected, voteCount }
post.comment.createпроверени{ postId, body: 1..1000 chars }Креиран коментар · HTTP 201.
post.reportпроверени{ postId, reason: "spam|personal-data|harassment|illegal|other", details? }{ reportId, status: "open" } · HTTP 201
admin.post.pendingпроверени + admin{}{ items: [{ isAnonymous, author: { userId, username, displayName }, ... }], count }
admin.post.moderateпроверени + admin{ postId, decision: "approved|rejected", note? }{ postId, status }
admin.report.listпроверени + admin{}{ items, count }
admin.report.resolveпроверени + admin{ reportId }{ reportId, status: "resolved" }

07 · Responses

Одговор што може сигурно да се следи

Успешен одговор има status completed и error null. Одбиено барање има status rejected, data null и структуриран error. Кај MySQL грешка се враќаат бројот, SQL state, конкретната порака и безбедна конекциска дијагностика без лозинката.

messageId

Клиентот генерира уникатен идентификатор.

→
replyToMessageId

Серверот го враќа истиот id за корелација.

→
nextExpectedTurn

Го покажува следниот turn во разговорот.

HTTPКогаВообичаен error.code
200Успешен system.ping.—
201Успешна регистрација.—
400Невалиден envelope или непозната операција.unsupported-version, missing-message-id, invalid-client, unsupported-client-app, invalid-conversation, missing-operation, invalid-data, invalid-operation-data, unsupported-operation
401Недостасуваат или не се точни credentials.missing-credentials, invalid-credentials
403Недоволни права, погрешен клиент или недостапна фирма.admin-required, operation-not-allowed-for-client, bookkeeping-access-required, company-access-required, obligation-access-denied
404Побараниот запис не постои.user-not-found, post-not-found, report-not-found, obligation-not-found, obligation-step-not-found
408Истечено барање.message-expired
409Корисничкото име или email веќе постои.user-already-exists
422Невалидни податоци или недостига деловен предуслов.authentication-mismatch, validation-error, invalid-confirmation, bookkeeping-database-required, company-database-required, company-registration-failed
429Надминато ограничување по IP.rate-limit-exceeded
503Регистрациската база е недостапна.database-unavailable, database-error

08 · Examples

Повик што можете веднаш да го приспособите

Примерот автоматски создава свежи UUID вредности и рок од пет минути, за да не копирате истечено барање.

cURL · system.ping
JavaScript · fetch
const now = new Date();
const payload = {
  schemaVersion: 1,
  messageId: crypto.randomUUID(),
  authentication: { username: "<username>", password: "<password>" },
  client: {
    appId: "idiot.mk",
    appVersion: "1.0.0",
    clientSessionId: crypto.randomUUID()
  },
  conversation: { id: crypto.randomUUID(), turn: 1 },
  operation: "system.ping",
  sentAtUtc: now.toISOString(),
  expiresAtUtc: new Date(now.getTime() + 5 * 60_000).toISOString(),
  data: {}
};

const response = await fetch("https://vps.xnet.mk:50443/api/commands", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify(payload),
  signal: AbortSignal.timeout(15_000)
});

const result = await response.json();
if (!response.ok || result.status !== "completed") {
  throw new Error(result.error?.code ?? `HTTP ${response.status}`);
}

09 · Checklist

Правила за стабилна интеграција

Овие правила треба да бидат дел од секоја клиентска имплементација, без оглед на програмскиот јазик.

Нови идентификатори

Не реупотребувајте messageId. Задржете clientSessionId само додека работи една клиентска инстанца.

UTC насекаде

Испраќајте ISO 8601 UTC времиња и краток expiresAtUtc за да се одбиваат застарени команди.

Безбедни логови

Редактирајте лозинки и големи бинарни/string полиња пред логирање.

Контролирано повторување

Не повторувајте write операција автоматски. Повторување разгледајте само кога error.retryable е true, со backoff и нови идентификатори.

Magmath 6 — XNet најава и сопствен профил

Клиентот magmath-6 е активен на XNet API. Поддржани се user.login, user.me, user.register, user.update, user.profile-picture.update и постојните change.request.* операции.

Секое барање содржи проверени authentication.username/password. Профилните операции го менуваат само најавениот корисник и го враќаат целиот освежен профил, вклучувајќи profilePicture. Business database операции сè уште не се отворени за овој клиент.

Magmath 6 договор, request полиња и production verification

domIO — домови, уреди и корисници

Точниот идентификатор client.appId: "domIO" е активен на XNet API v1 преку POST https://vps.xnet.mk:50443/api/commands.

На продукцискиот Listener се активни user.register, user.login, user.me и domio.* за каталогот. Домови, катови, простории и уреди може да се бришат со проверка на дозволи. Секое барање повторно ги проверува username/password. За физичкиот уред е потребен канал со потврда пред команда да може да успее.

domIO полиња, v1 envelope и примери за одговори

deldaste.com — јавен каталог на третмани

POST https://vps.xnet.mk:50443/api/commands · client.appId: "deldaste.com" · operation: "catalog.treatment.list"

Ажурирано 08.10.2026: Listener 1.4.2 ја поправа валидацијата на дозволените data полиња за јавните барања без authentication.

Операцијата е јавна и само за читање: нема authentication, корисничка најава, лозинка или session token. Филтерот gender е female или male; резултатот ги вклучува и третманите both. Се враќаат само активни третмани од активни категории, со цени, времетраење и серверскиот редослед.

Резервациите остануваат автентицирани, а административните промени и понатаму бараат Kiki Manager/admin дозвола.

Точен v1 envelope, полиња, JSON одговор, пагинација и грешки

Roomio — тарифници и серверски цени

room.rates.list · room.rates.save · room.rates.quote · room.reservation.request-status

Ажурирано 09.10.2026: availability batch quotes почнуваат по затворање на inventory reader-от. Кај резервација само првото лице мора да има име и презиме; придружните guest slots може да останат празни, но ги задржуваат ID, типот и позицијата.

Цените се пресметуваат на серверот по ноќ, со стандардни и сезонски тарифи, дополнителни легла, краткотрајни понуди и траен snapshot во резервацијата. Истиот договор важи за онлајн и LAN/offline Listener.

Точен договор, правила, дозволи, идемпотентност и грешки

ЗА СИТЕ АГЕНТИ · СИТЕ ПРОЕКТИ

Агенти: барањата за промени во API поднесувајте ги тука

Оваа главна страница е заедничката почетна точка за агентите од сите проекти. Ако ви недостига операција, добивате API грешка или ви треба промена во договорот, поднесете барање во заедничкиот ред на XNet.

  1. Прочитајте го упатството преку линкот подолу. Во барањето наведете го сопствениот client.appId, проектот, точните операции, грешката и очекуваниот резултат.
  2. Поднесете со change.request.submit на POST https://vps.xnet.mk:50443/api/commands, со обезбедените XNet username/password. Зачувајте го добиениот requestId.
  3. На сопственикот испратете само „Поднесено барање #ID — наслов“. Целиот опис останува во редот и се разгледува со Codex. Следете ја одлуката и резултатот со change.request.get; сопствените барања се достапни со change.request.list.

Поднесувањето не е одобрување. Сопственикот одлучува кои барања ќе се обработуваат; агентите не одобруваат сопствени барања.

Отвори упатство за поднесување барање →

Целосен договор и JSON пример во Markdown за агенти

10 · Codex bridge

Безбеден мост со теренски комуникатори

Теренските комуникатори одржуваат TLS WebSocket конекција и се докажуваат со сопствен ECDSA P-256 клуч и server challenge. Приватниот клуч останува DPAPI-заштитен на теренскиот компјутер; нема заеднички клуч, XNet корисник или лозинка.

✓

Listener-от извршува команди само преку loopback каналот. Оддалечен агент пристапува преку посебен gateway контролиран со XNet Update API клуч; ова не е дел од business API и не користи корисничко име или лозинка.

© XNet APIДокументација за интеграција · schemaVersion 1

Roomio — персонал и работни позиции

26 работни позиции во 9 оддели, преведени на 13 јазици, дефинирани и кеширани во Listener за сите хотели. Хотелска листа на вработени, регистрација во kesh.users и повеќе позиции по вработен, без доделување дозволи.

room.positions.list · room.personnel.list · room.personnel.register · room.personnel.positions

Полиња, одговори, пристап, идемпотентност и грешки

Almanac — евиденции за градинки

Локална имплементација; активирањето бара Listener deploy.

API договор, модули и правила за пристап

Almanac: unread support replies, 30-second cache and notifications (20.10.2026)