Подгответе клиент
Користете HTTPS клиент со JSON поддршка и разумен timeout. Заглавието Content-Type мора да биде application/json.
XNet · HTTPS · JSON
Практичен водич за сигурна интеграција со XNet: еден endpoint, предвидлив JSON договор и корелирани одговори за секое барање.
https://vps.xnet.mk:50443/api/commands
01 · Quickstart
Сите команди се испраќаат како UTF-8 JSON преку HTTPS. За секое барање креирајте нови идентификатори и краток рок на важност.
Користете HTTPS клиент со JSON поддршка и разумен timeout. Заглавието Content-Type мора да биде application/json.
Генерирајте нов messageId, стабилен clientSessionId и conversation id. Започнете со turn 1.
Повеќето барања содржат username и password; заштитените операции ги проверуваат во Users кешот. Документираните исклучоци се без најава.
Проверете HTTP статус, status и error. replyToMessageId секогаш треба да одговара на испратениот messageId.
Адреса на сервисот: Документацијата е на api.xnet.mk, а API повиците одат на vps.xnet.mk со задолжителната порта 50443. Користете ја целата адреса прикажана погоре; портата 443 моментално не е API endpoint.
HTTP endpoint-от се активира пред schema/cache иницијализацијата. /health може привремено да врати databaseReady: false; тогаш повторете ја операцијата откако кешот ќе се вчита.
02 · Contract
Структурата е верзионирана и обезбедува следливост меѓу апликации, клиенти и разговори. Полето data секогаш е JSON object.
{
"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": {}
}
| Поле | Тип | Значење |
|---|---|---|
| schemaVersion | integer | Мора да биде 1. |
| messageId | UUID | Нов, непразен идентификатор за секое барање. |
| authentication.username authentication.password | string | Задолжителни за заштитените операции, со документираните исклучоци за лиценца и XMan зачувување фирма. |
| client | object | Идентитет на апликацијата, верзија и непразен session UUID. |
| conversation | object | Непразен id и turn поголем од 0. |
| operation | string | Името на серверската функционалност. |
| expiresAtUtc | ISO 8601 / null | Ако е зададено, мора да биде во иднина. |
| data | object | Параметри за операцијата; никогаш JSON запишан како string. |
03 · Operations
Еден contract ги покрива автентикацијата, Finmath и root операциите, Обврски, јавниот feed, објавувањето, гласањето, коментарите, пријавите и администраторската модерација.
Проверува дали сервисот прифаќа и обработува валидни команди.
// request.data
{}
// response.data
{ "text": "pong" }Креира корисник само во локалната kesh.users база и целосно го освежува Users кешот.
{
"userId": 123,
"username": "developer",
"email": "dev@example.com",
"confirmed": true,
"emailDelivery": "not-required"
}| Категорија | operation | authentication | Намена |
|---|---|---|---|
| Auth | user.confirm-email user.resend-confirmation | credentials present | Задржани за компатибилност; email потврдата привремено не е потребна. |
| Auth | user.login user.me user.update user.profile-picture.update | verified credentials | Проверка на username/password, читање и промена на сопствениот профил без токени. |
| Finmath | catalog.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" и не избира база. |
| Feed | post.list post.get post.comment.list | credentials present | Јавни одобрени објави и коментари. |
| Content | post.create post.my post.vote post.comment.create post.report | verified credentials | Објавување, сопствена историја и интеракции. |
| Admin | admin.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.
Привремено не е потребно. Новите и постојните сметки серверот ги смета за потврдени.
Испрати username и password во authentication; успешниот одговор нема токени.
Ги проверува credentials повторно и враќа безбеден профил и isAdmin.
Ги менува сопствените профилни податоци само во kesh.users и го освежува Users кешот.
Ја менува само профилната слика. null или празен string ја отстранува; максималната должина е 700.000 знаци.
Дозволени origins се idiot.mk, www.idiot.mk и api.xnet.mk. Ограничувањето е 120 барања во минута по IP, а request body е најмногу 1 MB.
| Поле | Услов | Валидација |
|---|---|---|
| username | Задолжително | 3–45 знаци, без празни места. |
| password | Задолжително | 8–256 знаци. Се испраќа само преку HTTPS. |
| Задолжително | Валидна адреса, најмногу 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
Клиентот користи appId finmath-3. По најавата, response.data.finmath го содржи корисничкиот профил и сите достапни фирми; клиентот не се поврзува директно на MySQL.
По проверка на credentials враќа finmath.connections за избор на фирма или книговодство, без токени.
Со проверени username/password ги враќа активните држави и градови на mk, en или sq.
Креира реална фирма за најавениот сопственик. Задолжителниот requestId го прави повторувањето по timeout идемпотентно.
Пребарува од два знака и враќа само безбедни јавни полиња и стабилен companyGuid, без база или credentials.
Креира само pending барање со role=999; не доделува активен или администраторски пристап.
Бара одобрена книговодствена конекција, запишува директно во Hetz базата без stored procedures и го освежува локалниот kesh.
Проверува само zz_NNNNNNN_* табели. Непразна табела ја архивира фирмата; ако сите се празни, во deleted_companies LIKE 00_x.log_root ги зачувува целата фирма и сите user-connections како JSON, па ги брише само тие централни редови.
Креира книговодство со нова база со следниот слободен 04_ реден број и одобрена улога FinmathAccounter.
Ги спојува активните реални фирми од company_relations со валидните интерни фирми од my_settings и активните директни интерни конекции за истата книговодствена база. Позитивен ID и непразен краток назив се задолжителни; дозволен е и назив од еден знак, а zz_ работни табели не се услов.
Сите 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.
{
"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.mk | idiot — фиксна база |
finmath-3 | Базата се определува од одобрената избрана фирма. |
finmath-3-internal | Се користи базата на одобреното избрано книговодство. |
magmat-b, inmath-2 | Базата се определува од одобрената избрана фирма. |
obvrski | 09_obvrski — фиксна база; клиентот не испраќа име на база. |
root-manager | 00_x — Root Manager credentials, дозволени само за admin.*. |
domIO | Заеднички XNet идентитети и активни domio.* операции за домови, членови, катови, простории и уреди. Физичкиот provider сè уште не е поврзан. |
Секој друг appId се одбива со unsupported-client-app. Credentials се задолжителни во секој envelope; ознаката „присутни“ значи дека за таа јавна операција не се проверуваат, а „проверени“ значи дека username/password мора да одговараат на корисник од вчитаниот Users кеш. Само root-manager admin барањата се проверуваат во 00_x.usrs.
| operation | authentication | data | Главен 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[] } |
| operation | data | Главен 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. |
| Operation_Type | Намена | Operation_Type | Намена |
|---|---|---|---|
2 | ReadData | 3 | Insert |
4 | Update | 5 | Delete |
11 | ReadDocuments | 12 | ReadEmploeyees |
15 | RegisterFinancialWarrant | 18 | RegisterBankStatement |
25 | ArticleHistoryByYear | 41 | CreateTable |
51 | UpdateUser | 87 | OwnerReport |
92 | RegisterForexCalculation | 103 | CountryCityStructure |
110 | ArticleHistoryDetails | 124 | ProfitReport |
130 | ClientSubjectsRead | 131 | ClientSubjectSave |
140 | AlmanacCreateSchool | 310 | FeedbackCreateTicket |
311 | FeedbackListTickets | 312 | FeedbackGetTicket |
313 | FeedbackAddMessage | 333 | FinmathSalaryStatusList |
root.data е compatibility рута за постојната shared root библиотека, не општ SQL endpoint. Самата бројка Operation_Type не е доволна: data.request мора да го следи точниот Data_In модел за таа операција. Непренесените операции се одбиваат експлицитно.
Almanac · училишен веб-клиент и дозволени операции
Almanac · Google најава, поврзување профили и серверска проверка — потребна е Google Cloud конфигурација.
appId: "obvrski"| operation | data | Главен 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 } |
Кај анонимна објава серверот го зачувува вистинскиот автор, но post.list и post.get враќаат само author { displayName: "Анонимен корисник", username: null, profilePicture: null }. Само admin.post.pending го враќа вистинскиот author со userId.
| operation | authentication | data | Главен 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, конкретната порака и безбедна конекциска дијагностика без лозинката.
Клиентот генерира уникатен идентификатор.
Серверот го враќа истиот id за корелација.
Го покажува следниот 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 вредности и рок од пет минути, за да не копирате истечено барање.
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 само додека работи една клиентска инстанца.
Испраќајте ISO 8601 UTC времиња и краток expiresAtUtc за да се одбиваат застарени команди.
Редактирајте лозинки и големи бинарни/string полиња пред логирање.
Не повторувајте write операција автоматски. Повторување разгледајте само кога error.retryable е true, со backoff и нови идентификатори.
Клиентот magmath-6 е активен на XNet API. Поддржани се user.login, user.me, user.register, user.update, user.profile-picture.update и постојните change.request.* операции.
Секое барање содржи проверени authentication.username/password. Профилните операции го менуваат само најавениот корисник и го враќаат целиот освежен профил, вклучувајќи profilePicture. Business database операции сè уште не се отворени за овој клиент.
Точниот идентификатор client.appId: "domIO" е активен на XNet API v1 преку POST https://vps.xnet.mk:50443/api/commands.
На продукцискиот Listener се активни user.register, user.login, user.me и domio.* за каталогот. Домови, катови, простории и уреди може да се бришат со проверка на дозволи. Секое барање повторно ги проверува username/password. За физичкиот уред е потребен канал со потврда пред команда да може да успее.
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 одговор, пагинација и грешки
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 грешка или ви треба промена во договорот, поднесете барање во заедничкиот ред на XNet.
Поднесувањето не е одобрување. Сопственикот одлучува кои барања ќе се обработуваат; агентите не одобруваат сопствени барања.
10 · Codex bridge
Теренските комуникатори одржуваат TLS WebSocket конекција и се докажуваат со сопствен ECDSA P-256 клуч и server challenge. Приватниот клуч останува DPAPI-заштитен на теренскиот компјутер; нема заеднички клуч, XNet корисник или лозинка.
Listener-от извршува команди само преку loopback каналот. Оддалечен агент пристапува преку посебен gateway контролиран со XNet Update API клуч; ова не е дел од business API и не користи корисничко име или лозинка.
26 работни позиции во 9 оддели, преведени на 13 јазици, дефинирани и кеширани во Listener за сите хотели. Хотелска листа на вработени, регистрација во kesh.users и повеќе позиции по вработен, без доделување дозволи.
room.positions.list · room.personnel.list · room.personnel.register · room.personnel.positions
Локална имплементација; активирањето бара Listener deploy.
Almanac: unread support replies, 30-second cache and notifications (20.10.2026)