Kombine Flex Portal API · v1 · Integrationsvejledning
Byg din egen portal eller tilslut en AI-agent
API’et giver adgang til de samme oplysninger, som den officielle portal bruger. Du sender almindelige HTTPS-kald og får JSON tilbage. Du behøver hverken databaseadgang, et særligt SDK eller en særlig agentprotokol.
Kom i gang: Find API-adressen → log ind med en manager → hent /api/v1/session/me.
Hvad er klar nu? Driftsstatus, offentligt antal aktive brugere samt den indloggede managers navn, ikon, Tabs, adgang til banker/lokationer og handlingsrettigheder. Det er oplysningerne på portalens nuværende overblik. Users2-brugerlister findes via GetBankUsers. Andre bank-, lokations- og enhedsdata samt redigering er endnu ikke implementeret. En Tab i svaret betyder derfor ikke, at dens funktion allerede findes som API-kald.
Vælg tenantens API-domæne: https://api.{navn}.kombine.technology i produktion eller https://beta.api.{navn}.kombine.technology i beta. Navne: team, electrolux, portal, washco, finelec og nortec. Domænet er bundet til tenantens serverkonfiguration. KID, formularfelter og videresendte host-headere kan ikke skifte tenant. Tokens gælder kun deres tenant og miljø; log ind særskilt ved skift. En ukendt vært afvises med HTTP 400. Beta bruger aktuelt samme tenantdatabaser som produktion.
Antal køb den seneste time
GET /api/v1/public/statistics/purchases kan kaldes uden login. Swagger-navnet er GetPublicPurchases, og JavaScript-klienten har client.getPurchases().
Tæller rækker i sitets A{tenant}.Log1Hour med UserId >= eUserId.Users AND UserId <= eUserId.UsersLast AND Text NOT LIKE '%E' AND Amount < 0. Det er køb, ikke unikke kunder. SQL-tabellens collation bestemmer sammenligningen af E. Brugerintervallet følger den fælles enum: aktuelt 1001–99999 inklusive. Der tilføjes ikke bankfilter. Svaret indeholder også amount = -SUM(Amount)/100 og currency = MAX(Currency). Uden køb returneres 0 og null. MAX(Currency) forudsætter samme valuta blandt købene; der foretages ingen valutaomregning.
Log1Hour vedligeholdes af databasen med oprydning hvert minut. Optællingen bruger tabellens indhold ligesom den aftalte SQL, så tidsvinduet afhænger af denne oprydning. sinceUtc er den nominelle start én time før measuredAtUtc, og lookbackHours er 1. tenantKid angiver sitet, og count er antallet. Klienten kan ikke skifte tenant eller filtre.
Resultatet caches i ét minut pr. API-instans. Kortet opdaterer automatisk hvert minut, mens siden er åben. Samtidige kald deler én databaseforespørgsel. HTTP 503 med Retry-After: 60 betyder utilgængelig, ikke nul. De almindelige CORS-regler gælder for JavaScript fra andre sites.
const response = await fetch('https://api.team.kombine.technology/api/v1/public/statistics/purchases');
if (!response.ok) throw new Error('HTTP ' + response.status);
const purchases = await response.json();
console.log(purchases.count, purchases.amount, purchases.currency);
Offentligt uden login
GET /api/v1/public/statistics/active-users — Antal aktive brugere for sitets tenant. Swagger: Public → GetPublicActiveUsers.
Tallet tæller unikke kombinationer af bank og bruger i tenantens aktuelle Log7 med bruger-id fra 1001 til og med 99999, bank-id mindst 1000 og MS2000 strengt nyere end 100 dage før opgørelsen i UTC. Flere rækker for samme bank/bruger tæller én gang; samme bruger-id i to banker tæller to gange. Det beskriver en nyere Log7-post, ikke nødvendigvis et login. Der filtreres ikke på brugerens Enabled eller Deleted.
Dette samlede tal er offentligt og uafhængigt af managerens adgang. Ingen personer eller enkelte bankers tal udleveres. Sitet bestemmer tenant; kaldet tager ingen KID, datoperiode eller andre filtre.
tenantKid identificerer sitets tenant, count er antallet, lookbackDays er 100, sinceUtc er den eksklusive tidsgrænse, og measuredAtUtc er opgørelsens tidspunkt. Svaret caches i op til 5 minutter pr. API-instans. Samtidige besøg deler én optælling, og der er ingen baggrundspolling. Ved databasefejl returneres HTTP 503 med Retry-After: 60; vis utilgængelig, ikke nul. Et vellykket svar med count 0 betyder faktisk nul.
const response = await fetch('https://api.team.kombine.technology/api/v1/public/statistics/active-users');
if (!response.ok) throw new Error('HTTP ' + response.status);
const statistics = await response.json();
console.log(statistics.count, statistics.measuredAtUtc);
JavaScript-klienten har også client.getActiveUsers(). For JavaScript på et andet site skal API’ets Cors:AllowedOrigins indeholde klientens præcise origin, som beskrevet nedenfor.
Flere managers må have samme e-mailadresse, hvis adgangskoderne er forskellige. Login finder den matchende kombination af e-mail og adgangskode; matcher flere konti samme kombination, afvises login med 401.
Mislykkede loginforsøg kan gemmes som interne JSON-diagnoser. Klientens statuskoder og svar ændres ikke; interne årsager som dubleret kombination af e-mail og adgangskode udleveres ikke gennem login. Drift kan korrelere anmodningens trace-id med API-loggen. Adgangskoder og tokens må aldrig medsendes i fejlrapporter.
Login og managerindstillinger hentes fra sitets egen A{TenantId:D4}.Log7, BankId 0. D4 betyder tenant-id med mindst fire cifre: Team 166 bruger A0166.Log7. Tenant vælges i serverens PortalSite:TenantId; der er ingen fallback til en anden tenants managerdatabase.
Manageren skal have Enabled = 1. Mangler Deleted-rækken (eller er den SQL NULL), bruges 0: ikke slettet. En eksisterende ugyldig Deleted-værdi eller en positiv sletningsværdi blokerer stadig login.
1. Fra API-adresse til første login
API-adressen for dette tenant-site er https://api.team.kombine.technology. Brug API-adressen, ikke portalens adresse.
Eksemplerne bruger automatisk adressen på det API-site, hvor du læser vejledningen. Beta viser beta-adressen. Uden JavaScript vises Team-produktionsadressen; kontrollér adressen før brug. Du kan ikke skifte tenant med et ekstra felt, en query-parameter eller en header. Site og rettigheder bestemmes på serveren.
| Kald | Formål | Login? |
|---|---|---|
GET /api/v1/public/statistics/purchases | Antal køb den seneste time | Nej |
GET /api/v1/public/statistics/active-users | Antal aktive brugere for sitets tenant | Nej |
GET /api/v1/status | Tjek, om API’et svarer. Tester ikke MySQL. | Nej |
POST /api/v1/session/login | Byt managerens email og password til et midlertidigt adgangstoken. | Email og password i JSON |
GET /api/v1/session/me | Hent din egen profil og dine aktuelle rettigheder samlet. | Adgangstoken |
Prøv uden at skrive et program
- Åbn Swagger, og vælg Portal integrations v1. Swagger er en webside, hvor du kan læse om og afprøve API-kaldene.
- Åbn GetPortalStatus, vælg Try it out og derefter Execute. Et svar med HTTP 200 betyder, at kaldet lykkedes.
- Åbn LoginManager. Erstat eksemplets email og password med din managers oplysninger, og vælg Execute. Eksempeloplysningerne er opdigtede og kan ikke bruges til login.
- Kopiér kun værdien af
accessTokenfra svaret, uden anførselstegn. Klik Authorize, indsæt den under ManagerBearer, og godkend. Swagger tilføjer selvBearer. - Kør GetCurrentManager. Svaret indeholder de oplysninger, du kan bruge til profil og adgangskort i din portal.
En manager skal være aktiveret og ikke slettet. Manglende Tabs eller bankadgang forhindrer ikke selve login; forklar i din portal, hvilken adgang der mangler.
Sådan ser HTTP-kaldene ud
POST https://api.team.kombine.technology/api/v1/session/login
Content-Type: application/json
Accept: application/json
{"email":"[email protected]","password":"<dit password>"}
Send det oprindelige password over HTTPS. API’et håndterer kontrollen; klienten skal ikke encode eller hashe passwordet.
{
"accessToken": "<dit adgangstoken>",
"expiresIn": 3600,
"tokenType": "Bearer"
}
GET https://api.team.kombine.technology/api/v1/session/me
Authorization: Bearer <dit adgangstoken>
Accept: application/json
Tokenet gælder i én time fra login. Behandl det som en hemmelig tekststreng: det er ikke en JWT, du skal decode. Genbrug det til dine kald, og log ind igen, når det udløber. Der findes endnu ikke refresh tokens eller et API-kald til at tilbagekalde ét token. Ved logout fjerner din klient sit token; en eventuel kopi kan stadig virke indtil udløb eller tilbagekaldelse via konto/password.
Et helt eksempel i PowerShell 7
Kopiér blokken til PowerShell 7. Dialogen beder om managerens email og password. Eksemplet viser profilen og skriver hverken password eller token ud. Lokalt skal .NET’s udviklingscertifikat være betroet; brug dotnet dev-certs https --trust ved lokal udvikling.
$api = 'https://api.team.kombine.technology'
$credential = Get-Credential -Message 'Manager email and password'
$session = $null
$body = $null
$headers = $null
try {
$body = @{
email = $credential.UserName
password = $credential.GetNetworkCredential().Password
} | ConvertTo-Json -Compress
$session = Invoke-RestMethod "$api/api/v1/session/login" `
-Method Post -ContentType 'application/json' -Body $body -TimeoutSec 15
$headers = @{ Authorization = "Bearer $($session.accessToken)" }
$profile = Invoke-RestMethod "$api/api/v1/session/me" `
-Headers $headers -TimeoutSec 15
$profile | ConvertTo-Json -Depth 6
}
catch {
if ($_.Exception.Response) {
Write-Warning "HTTP $([int]$_.Exception.Response.StatusCode). See the error table."
} else {
Write-Warning 'Could not reach the API. Check the address, connection, and certificate.'
}
}
finally {
$body = $null
$headers = $null
$session = $null
$credential = $null
}
2. Forstå managerens oplysninger og adgang
Dette er et opdigtet svar. Brug altid de faktiske værdier fra API’et.
{
"kid": "3E7Q46o3B9ACA01h",
"retentionDays": 30,
"organisation": "Example organisation",
"name": "Eksempelmanager",
"icon": "house",
"tabs": [4, 12],
"hasBankAccess": true,
"tabDetails": [{"id": 4, "name": "Bank1"}, {"id": 12, "name": "Dashboard1"}],
"resourceGrants": [{"kid": "3E7Q14o2Ab", "scope": "Bank"}],
"navigationBanks": [{"kid": "3E7Q14o2Ab", "name": "Example bank", "icon": "house"}],
"operationPermissions": [
{"resource": "Bank", "level": "Read", "canRead": true, "canWrite": false, "canCreate": false},
{"resource": "Location", "level": "Write", "canRead": true, "canWrite": true, "canCreate": false},
{"resource": "Unit", "level": "Create", "canRead": true, "canWrite": true, "canCreate": true},
{"resource": "User", "level": null, "canRead": false, "canWrite": false, "canCreate": false}
]
}
| Felt | Betydning og anvendelse |
|---|---|
organisation | Valgfri organisation fra managerens eSetting.Organisation i A{TenantId:D4}.Log7, BankId 0. Tom streng, når den mangler. Portalen viser den under navnet, når den er udfyldt. Kun visning; giver ingen rettigheder. Hentes i samme opslag og følger managerens cache på højst 60 sekunder. |
retentionDays | Antal dage efter sletningen, hvor manageren må se en slettet bank, lokation, enhed, bruger eller reservation. Hentes fra eSetting.RetentionDays i A{TenantId:D4}.Log7, BankId 0. Manglende, negative eller ugyldige værdier giver 0, som skjuler slettede objekter. Feltet ændrer ikke Kids-, Tab- eller handlingsrettigheder og styrer ikke fysisk sletning. Caches sammen med manageren i højst 60 sekunder. GetBankUsers håndhæver grænsen. Kommende detaljer, optællinger og søgninger skal også håndhæve den. |
kid | Managerens ID som tekststreng. Gem og send værdien uændret. me returnerer kun den indloggede manager. Et ID giver ikke adgang i sig selv. |
name, icon | Visningsnavn og ikonidentifikator. Navn kan være tomt. house kan vises fra https://static.kombine.services/icon1/house.svg. Brug et kendt, gyldigt ikonnavn, og ellers et standardikon; indsæt ikke rå HTML eller en vilkårlig URL fra feltet. |
tabs, tabDetails | De tilladte sider, som vi kalder Tabs. ID’erne svarer til eTab; navnene er stabile enum-navne, ikke oversatte sidetitler. Brug ID’et som nøgle og oversæt visningen i din egen portal. Ukendte ID’er må ikke antages at give en kendt rettighed. |
hasBankAccess | Om der er mindst én bank- eller lokationsadgang på dette site. Det er ikke en generel tilladelse til alle data. |
resourceGrants | De konkrete områder, manageren må have adgang til. Se reglerne nedenfor. Arrayet indeholder ikke banknavne eller selve bankdata. |
operationPermissions | Fire uafhængige handlingsrettigheder: Bank, Location, Unit og User. Brug de beregnede canRead, canWrite og canCreate til at vise relevante handlinger. |
Hvilke banker og lokationer?
Et objekt i resourceGrants gælder kun den angivne tenant. Flere objekter giver adgang til flere områder.
scope = "Tenant": KID’en beskriver hele sitets tenant. Vis “Alle banker” og “Alle lokationer”.scope = "Bank": KID’en beskriver én bank med alle dens lokationer.scope = "Location": KID’en beskriver én bestemt lokation i en bank.
scope beskriver adgangens omfang. Brug ID-strengen uændret; udled ikke rettigheder eller objektnavne fra den.
Sådan bruger du KID-strenge
En KID er et ID fra API-svarets kid-felt. Behandl det som en almindelig tekststreng i alle programmeringssprog. Gem og send hele værdien uændret, inklusive store og små bogstaver. Du skal ikke afkode, opdele eller selv konstruere den. Intet Kombine-bibliotek er nødvendigt.
Brug bankens kid fra navigationBanks til bankkald, lokationens kid fra lokationslisten til lokationskald og brugerens kid fra brugerlisten til brugerkald. Brug encodeURIComponent(kid) i JavaScript, når et ID indsættes i en URL. Brug felter som name til visning og scope til adgangens omfang.
Et ID er hverken et login-token eller en tilladelse. Serveren kontrollerer sitet og managerens rettigheder ved hvert beskyttet kald. Et ID kan ikke skifte tenant eller give flere rettigheder.
Denne version af kontrakten erstatter de tidligere separate felter userId, tenantId, bankId og locationId med KID-strenge. Opdater klienter, der brugte de gamle felter. De eksisterende login- og profilruter er uændrede.
Hvad må manageren gøre?
level | Læs | Ret | Opret |
|---|---|---|---|
Read | Ja | Nej | Nej |
Write | Ja | Ja | Nej |
Create | Ja | Ja | Ja |
null | Nej | Nej | Nej |
En manglende eller tom rettighedsindstilling bliver til Read på serveren. En ugyldig, udfyldt indstilling giver null og ingen handlinger. Handlingsrettigheder udvider aldrig adgang til Tabs, banker eller lokationer. En skrive- eller oprettelsesret betyder ikke en automatisk sletteret.
Vis “Du har endnu ikke adgang til nogen banker”, hvis hasBankAccess er false. Vis “Du har endnu ikke adgang til nogen Tabs”, hvis tabs er tomt. Begge beskeder kan være relevante samtidig. En netværksfejl eller HTTP 503 skal vises som en fejl ved hentning, ikke som manglende rettigheder.
Klientens knapper er hjælp til brugeren. API’et skal kontrollere konto, site, Tab, objektets område og handling, før det returnerer eller ændrer forretningsdata. En klient må ikke kunne give sig selv rettigheder ved at ændre JSON eller et link.
3. Fejl og hvad klienten skal gøre
Kontrollér HTTP-status først. Login kan ved 403 give et stabilt code-felt, eksempelvis {"code":"disabled"}. Andre fejl bruger normalt Problem Details med status, title og eventuelt traceId; valideringsfejl kan også have errors. En proxy eller webserver kan sende en tom fejl eller HTML, så kræv ikke JSON for at håndtere en fejl.
| Status / kode | Hvad betyder det? | Vis eller gør |
|---|---|---|
| 400 | Ugyldigt JSON, email eller manglende felter. | Ret input. Email højst 254 tegn; password højst 1.024 tegn. |
| 401 ved login | Email/password passer ikke til en gyldig manager. | “Email eller password er forkert.” Undgå automatisk gentagelse. |
401 ved me | Token mangler, er ugyldigt/udløbet, eller konto/password er ændret. | Fjern token og vis login igen. Svaret afslører ikke den konkrete kontotilstand. |
403 / disabled | Manageren er deaktiveret. | “Din manager er deaktiveret. Kontakt administratoren.” |
403 / deleted | Manageren er slettet. | “Din manager er slettet. Kontakt administratoren.” |
403 / account-settings | Kontoens aktiverings-/sletteindstillinger mangler eller er ugyldige. | “Din manager er ikke korrekt opsat. Kontakt administratoren.” |
| 413 / 415 | For stor login-forespørgsel / forkert indholdstype. | Send kun email og password som application/json. Grænsen for login-body er 8.192 bytes. |
| 429 | For mange loginforsøg. | Vent mindst Retry-After sekunder (aktuelt 60). Brug 60 sekunder, hvis headeren mangler. |
| 503 | API’et kan ikke hente de nødvendige data. | Vis midlertidig driftsfejl. Tilbyd et nyt forsøg efter en pause. |
403-årsagen ved login gives først efter korrekt password. Oversæt koderne i din egen brugerflade. Byg ikke logik på de engelske fejltekster eller et bestemt traceId.
4. Din egen portal
Komplet JavaScript-eksempel
Åbn det fungerende JavaScript-eksempel. Det har felter til API-adresse, email og password samt knapper til status, login, opdatering af profil og logout. Eksemplet bruger almindelig fetch og kræver ingen npm-pakker eller framework.
Vil du bruge det i din egen portal, så kopier portal-api.mjs til din JavaScript-mappe. Filen er et lille, valgfrit eksempel; du kan også bruge direkte fetch-kald som vist nedenfor. Brug ét klientobjekt pr. bruger og API-site:
import { createPortalClient } from './portal-api.mjs';
const portal = createPortalClient('https://api.team.kombine.technology');
// email og password kommer fra din loginformular.
await portal.login(email, password);
const manager = await portal.getProfile();
// Vis manager.name, manager.tabDetails og manager.operationPermissions.
// Kald portal.getProfile() ved manuel opdatering og portal.logout() ved logout.
Indlæs din egen scriptfil med <script type="module" src="./app.mjs"></script>. Gem eksempelfilerne på din egen webserver; åbn dem ikke via file://, og importér ikke JavaScript-filen direkte fra et andet API-domæne. Det samme klientmodul kan bruges i Node.js med indbygget fetch. JavaScript, der kører på en server, behøver ikke CORS.
Klienten gemmer kun tokenet i hukommelsen. Den genbruger tokenet, rydder det ved HTTP 401 og giver fejl med status, code og ved HTTP 429 retryAfter. Netværks-, certifikat-, timeout- og CORS-fejl har ikke nødvendigvis HTTP-status. Der er ingen automatisk gentagelse eller polling. På en Node.js-server må klientobjektet ikke deles mellem brugere.
Portal med egen server
Lad din server kalde API’et og opbevare adgangstokenet i den enkelte brugers beskyttede session. Det er også modellen i den officielle Blazor-portal. Del aldrig én managers session mellem flere brugere. Browseren bruger din portals eget login/cookie, mens serveren sender bearer-tokenet til API’et. Det kræver ikke CORS.
Browseren kalder API’et direkte
Det er også muligt. Hvis din portal ligger på en anden adresse end API’et, skal API-administratoren tilføje dens præcise origin under Cors:AllowedOrigins. En origin er protokol, værtsnavn og eventuel port, uden sti eller afsluttende skråstreg. Listen er tom som standard.
{
"Cors": {
"AllowedOrigins": ["https://min-portal.example", "https://localhost:5173"]
}
}
Dette er serverkonfiguration og kræver genstart. Miljøvariablen for første adresse er Cors__AllowedOrigins__0. Kun tilføjede origins kan læse svar fra integrationskaldene gennem browseren. Login og rettighedskontrol gælder stadig. CORS er en browserregel, ikke adgangskontrol for serverprogrammer.
Hvis din udviklingsside kører på http://localhost:5173, skal netop den adresse tilføjes; https://localhost:5173 er en anden origin. Brug altid API’ets HTTPS-adresse. Browseren sender selv OPTIONS før relevante kald; API’et håndterer dette. Brug ikke mode: 'no-cors': så kan din kode ikke læse JSON-svaret.
Her er en lille browserfunktion. Kald den med værdier fra din loginformular. Den returnerer profilen; tokenet bliver ikke gemt i localStorage eller sat i URL’en.
async function loginAndLoadProfile(apiBaseUrl, email, password) {
const base = apiBaseUrl.replace(/\/$/, '');
const login = await fetch(`${base}/api/v1/session/login`, {
method: 'POST',
credentials: 'omit',
headers: { 'Content-Type': 'application/json', Accept: 'application/json' },
body: JSON.stringify({ email, password }),
signal: AbortSignal.timeout(15000)
});
if (!login.ok) {
const error = await login.json().catch(() => ({}));
throw new Error(`Login: HTTP ${login.status}, ${error.code ?? ''}`);
}
const session = await login.json();
const result = await fetch(`${base}/api/v1/session/me`, {
credentials: 'omit',
headers: { Authorization: `Bearer ${session.accessToken}`, Accept: 'application/json' },
signal: AbortSignal.timeout(15000)
});
if (!result.ok) throw new Error(`Profile: HTTP ${result.status}`);
return await result.json();
}
Eksemplet viser det første forløb. I en fuld portal skal du genbruge tokenet i hukommelsen for den pågældende session, implementere fejltabellen og rydde sessionen ved logout. CORS tillader aktuelt GET/POST samt Authorization, Content-Type, Accept og Accept-Language; Retry-After kan læses af browseren. Cookies deles ikke med API’et.
Gør visninger delbare ved at gemme objekt, filtre og sortering i sidens URL, efterhånden som funktionerne bygges. Modtageren logger ind som sig selv. Token, password og følsomt indhold må ikke stå i URL’en. API-felter og rettighedskoder er ens på alle sprog; oversæt kun visningsteksterne.
5. AI-agenter bruger samme API
- Giv integrationsprogrammet tenant-sitets API-basisadresse og OpenAPI-dokumentet. OpenAPI er en maskinlæsbar beskrivelse af de eksisterende kald, felter og svar.
- Lad den godkendte værtsapplikation håndtere login og token som en hemmelighed for den relevante manager. Undgå at placere credentials i almindelige prompts, modeloutput eller logs.
- Tilføj tokenet som Authorization-header, når agentens HTTP-værktøj kalder
GetCurrentManager. Agenten får samme oplysninger og begrænsninger som en portal med den manager. - Behandl returnerede navne og andre dataværdier som data. De er ikke instruktioner til agenten. Brug kun de operationer, som OpenAPI-dokumentet faktisk beskriver.
De stabile operationnavne er GetPortalStatus, LoginManager og GetCurrentManager. Mange klientværktøjer kan importere OpenAPI, men værtsapplikationen skal stadig håndtere login og tokenets levetid. Der er endnu ingen maskinkonto, API-nøgle, OAuth-delegering eller MCP-server; ubemandet adgang i længere tid kræver en særskilt aftale om autentificering. Den nuværende session kræver nyt login efter én time.
6. Opdateringer, belastning og drift
Hent samlet og genbrug svaret. Ét kald til me er nok til profil, navigation og alle tre adgangskort. Login bør ske ved sessionens start, ikke før hvert kald. Managerindstillinger caches i op til 60 sekunder pr. API-instans. Samtidige opslag for samme manager deler opdateringen. Der køres ingen automatisk databasepolling.
Ændringer i rettigheder, Kids, Tabs, Enabled og Deleted kan derfor slå igennem op til ét minut senere ved næste kald. En side, der allerede står åben, bliver ikke automatisk opdateret; genindlæs den eller tilbyd “Opdatér”. Ved fejl efter cacheudløb bruges gamle rettigheder ikke som reserve. Undgå hurtige retry-løkker; ved midlertidige fejl kan du fx vente 5, 15 og 30 sekunder og derefter vise fejlen.
Login har aktuelt en grænse på 10 forsøg pr. normaliseret email pr. minut og 120 pr. kilde-IP pr. minut, pr. API-instans. Serverportaler kan dele kilde-IP, så login skal ikke gentages unødigt. Bruger- eller hostnavne og databasedetaljer skal ikke bruges som credentials.
Til den, der driver API’et
Publicér API’et over HTTPS med det korrekte tenant-site, hostnavne, databaseforbindelse og beskyttede, vedvarende Data Protection-nøgler. Web og API skal bruge samme tenant. Eksterne klienter får API-adressen og deres manageradgang; databasepassword bliver på serveren. Ved flere replikaer skal nøgler for samme site deles sikkert, og loginbegrænsning koordineres. Cache er lokal pr. instans. Konfigurér kun forwarded headers fra kendte reverse proxies.
Swagger, OpenAPI og begge vejledninger følger med API-publiceringen og styres af ApiDocumentation:Enabled (standard: true). Vejledningerne findes på /docs/da og /docs. Denne ændring publicerer ikke i sig selv API’et på internettet.
GET /api/v1/database/status er kun til drift. Det ligger i et separat diagnostikdokument og kræver en anden slags token: en JWT med scope portal.diagnostics. Managerens token virker ikke her. Brug /api/v1/status eller /health til almindeligt svartjek uden MySQL-kald.
Når API’et udvides
Nye portaloplysninger og handlinger skal implementeres i det fælles API, før Web tager dem i brug, og dokumenteres her og i OpenAPI. Eksterne klienter skal tolerere ekstra JSON-felter og ukendte fremtidige enum-værdier uden at give flere rettigheder. Eksisterende v1-felters betydning må ikke ændres skjult; uforenelige kontraktændringer kræver en ny version. Store lister skal have serverfiltrering og sideopdeling, når de tilføjes.
Banknavne i navigationen
Det eksisterende GET /api/v1/session/me (GetCurrentManager) indeholder navigationBanks. Genbrug dit bearer-token og læs profile.navigationBanks i JavaScript. Hvert objekt har kid, name og icon; der kræves ingen numeriske id'er eller ekstra kald. Brug KID som objektets identitet, og kopiér den præcise streng ved deling.
Navnene kræver en aktiv konto, mindst én tilladt Tab, Bank Read og bank- eller lokationsadgang på dette site. En lokationsadgang giver kun bankens navn og ikon til navigationen, aldrig adgang til hele bankens data. Arrayet er tomt ved adgang til alle banker (denne liste kommer senere), manglende Tabs, manglende adgange eller ugyldig Bank-rettighed. Handlinger under hver Tab kræver fortsat selvstændig kontrol af rettigheder.
Navn og ikon hentes fra sitets Log24, EntryType Settings (2), LocationId 0 og UnitId 0, med eSetting.Name (99) og Icon (37). Manglende værdier er tomme strenge: vis en tekst for bank uden navn og et lokalt reserveikon. Vis tekst som tekst, aldrig HTML. Et sikkert ikonnavn som house kan bruges til https://static.kombine.services/icon1/house.svg. Portalen viser bankens KID ved mouseover og tilbyder kopiering ved højreklik.
Navne og ikoner caches ét minut pr. bank pr. API-instans og genbruges mellem managers. Manglende cacheværdier hentes samlet i grupper på højst 64 banker. Rettigheder kontrolleres uafhængigt med managerens tidsbegrænsede snapshot. Der søges ikke efter banker ved adgang til hele tenanten. Databasefejl giver 503, som ikke må fortolkes som en tom rettighedsliste. Prøv senere; ugyldig eller udløbet session giver 401. Navigationsnavnene er ikke en bankdetaljevisning eller en liste over slettede objekter.
tabDetails[].icon kommer fra AttributeMetaIcon på den tilsvarende eTab, fx bank_building. Brug samme sikre ikonadresse som for banker. En tom streng betyder intet ikon; vis et lokalt reserveikon. Ikonerne læses fra den fælles enum uden databaseopslag.
userKid vælger én præcis beboer i banken: await client.getBankUsers(bankKid, { userKid: residentKid }). Brug en kanonisk User-KID fra et tidligere svar. KID skal tilhøre sitets tenant og den angivne bank og må ikke kombineres med filter eller cursor (400). Samme manager-, Tab-, User Read-, lokations- og RetentionDays-regler gælder. Svaret har nul eller én række og ingen fortsættelsescursors. En manglende eller ikke-synlig beboer giver en tom liste; det afslører ikke, om beboeren findes. Portalens delbare visning bruger /banks/{pageKid}, hvor sidens bank-KID indeholder både Tab=Users2 og beboerens UserId. Ældre ?resident={userKid}-links viderestilles; browserens arbejdsområde gemmer kun lokale genveje og giver ingen rettigheder.
Wildcards i filter: * matcher nul eller flere tegn, og ? matcher ét tegn. Eksempel: filter=1568-*002* eller filter=Anna?*. Der søges fortsat efter indhold i Nummer ELLER Navn, også uden wildcards. Andre tegn, herunder SQL-tegnene % og _, behandles bogstaveligt. URL-kod filteret med URLSearchParams eller encodeURIComponent. Matchning sker i API-hukommelsen på det eksisterende cachede grundlag; der genereres ingen wildcard-SQL.
filter søger efter en deltekst i number ELLER name, uden forskel på store/små bogstaver (sprogneutral sammenligning). Højst 200 tegn; mellemrum i begyndelsen og slutningen fjernes. Tomt filter viser hele den autoriserede liste. Filtrering sker før sideopdeling og bruger det fælles cachede sorteringsgrundlag, også med identity. Bevar filteret sammen med cursor; ændret filter kræver en ny forespørgsel uden cursor, ellers returneres 400. Rettigheder og RetentionDays gælder stadig. Eksempel: await client.getBankUsers(bankKid, { sort: 'name', direction: 'asc', filter: 'anna', pageSize: 25 }). URL-kod filtertekst. Et delt link indeholder søgeteksten.
icon indeholder brugerens eSetting.Icon (37) som et valideret eIcon-navn. Manglende, tomme, ukendte værdier og none giver user. Både lagrede enum-navne og numeriske enum-værdier understøttes. Vis ikonet fra https://static.kombine.services/icon1/{icon}.svg. Ikonet hentes med sidens øvrige indstillinger og følger samme adgangskontrol og cache; der laves ikke et separat databaseopslag pr. bruger.
Vælg sort=number|name|location|deleted og direction=asc|desc. Sorteringen gælder hele den liste, manageren må se, også ved løbende indlæsning. Udeladt sort bruger fortsat den tidligere identity-rækkefølge (kun asc). Numeriske numre sorteres numerisk før tekstnumre; navne og tekstnumre sammenlignes uden forskel på store/små bogstaver med en sprogneutral ordinal rækkefølge. Location er det laveste synlige lokationsnummer med Access eller NoAccess. Tomme værdier og ikke-slettede brugere står først i ASC og sidst i DESC. Slettede sorteres på slettetidspunkt. Brugerens identitet afgør rækkefølgen ved ens værdier.
const page = await client.getBankUsers(bankKid, {
pageSize: 25, sort: 'name', direction: 'asc'
});
const next = page.nextCursor
? await client.getBankUsers(bankKid, {
pageSize: 25, sort: 'name', direction: 'asc', cursor: page.nextCursor
})
: null;
Bevar sort, direction og pageSize under indlæsning. Når sorteringen ændres, start uden cursor. En cursor til en anden sortering eller retning giver 400. Sorterede cursors er positioner i den aktuelle, autoriserede liste; ændrede data eller rettigheder kan flytte positioner mellem kald. Et delt link giver aldrig afsenderens rettigheder.
Til sortering læses et fælles grundlag med fire indstillinger én gang og genbruges i op til 60 sekunder på tværs af managers og sorteringsvalg. API'et filtrerer rettigheder og sorterer i hukommelsen; kun den valgte portion får hentet øvrige oplysninger. Der udføres ingen COUNT, SQL OFFSET eller opslag pr. bruger. Kold cache kræver gennemlæsning af bankens almindelige brugere; meget store banker kan ramme timeout og give 503. Gentag ikke straks automatisk. Identity-tilstand bruger fortsat den begrænsede gennemgang på højst 1.000 kandidater og scanLimitReached.
Den officielle portal bruger GetBankUsers til løbende indlæsning ved scrolling. Eksterne portaler kan gøre det samme: hent én nextCursor ad gangen, genbrug svaret og stop ved null. Ved fejl stoppes automatisk indlæsning; vis fejl og tilbyd et nyt forsøg. Autorisation gælder for hvert kald, også når cursoren kommer fra en kollegas link.
Brugere i en bank (Users2)
GET /api/v1/banks/{bankKid}/users?pageSize=25 · operation GetBankUsers. Brug bankens KID fra navigationBanks eller et bank-scope i resourceGrants. Send managerens bearer-token. Ingen separate tenant-, bank- eller bruger-id'er sendes.
const page = await client.getBankUsers(bankKid, { pageSize: 25 });
for (const user of page.items) console.log(user.kid, user.name, user.number);
if (page.nextCursor) {
const next = await client.getBankUsers(bankKid, {
pageSize: 25, cursor: page.nextCursor
});
}
Svaret har items, previousCursor, nextCursor og scanLimitReached. Hver bruger har kid, name (99), number (1824), deletedAt (1996, UTC eller null), locations (1809, KID og Access/NoAccess), tags (2977, KID og eTagState) samt attributes (2978, eUserAttribute-navn og value; negativ værdi betyder ingen talværdi). Manglende tekst og lister er tomme; manglende Deleted betyder ikke slettet.
API'et kræver aktiv manager, Users2 (53), User Read og et passende KID-scope. Bank-/tenantadgang omfatter alle bankens almindelige brugere. Ved lokationsadgang vises kun brugere tilknyttet mindst én tilladt lokation med Access eller NoAccess; andre lokationer fjernes fra svaret. Navn, nummer, brikker og attributter er brugerens fælles bankdata. RetentionDays begrænser slettede brugere; ugyldig sletteværdi skjuler brugeren. eUserId.Users til og med UsersLast medtages, ikke manager- eller servicekonti.
pageSize er 1–100 (standard 25). Standardtilstanden identity bruger stigende brugeridentitet. Send en returneret cursor uændret; null betyder ingen fortsættelse i den retning. Cursoren kan deles med en kollega, men giver aldrig rettigheder. Kollegaens egne rettigheder gælder, så indholdet kan være anderledes. Listen er ikke et fastlåst øjebliksbillede, hvis data ændres mellem sider.
I identity-tilstand caches portioner i højst 60 sekunder; der bruges hverken fuld optælling eller OFFSET. Højst 1.000 kandidater undersøges pr. kald. scanLimitReached=true betyder, at siden kan være kort eller tom: fortsæt med cursoren. Poll ikke alle sider automatisk.
400: ugyldig KID, cursor eller sidestørrelse (åbn første side igen). 401: log ind igen. 403: manglende Tab, scope eller User Read. 503: midlertidig datafejl; vis en fejl og prøv senere, ikke en tom liste. Bearer-token bliver aldrig lagt i portalens delbare URL. JavaScript kræver en tilladt CORS-origin som beskrevet ovenfor.
Users2: Hver post i locations indeholder også icon, lokationens eIcon-navn fra eSetting.Icon i Log24. Manglende eller ugyldigt ikon giver house. Ikoner caches i op til ét minut. state er fortsat Access eller NoAccess. Portalen viser ikonet med state som data-parameter og lokationsnummer/state/KID ved mouseover.
Lokationer på bankoverblik
GET /api/v1/banks/{bankKid}/locations (operationId: GetBankLocations) returnerer et array af {kid,name,icon}. Brug bankens KID uden Tab og managerens bearer-token.
const response = await fetch(`${api}/api/v1/banks/${encodeURIComponent(bankKid)}/locations`, {
headers: { Authorization: `Bearer ${token}` }
});
if (!response.ok) throw new Error(`Location request failed: ${response.status}`);
const locations = await response.json();Kræver aktiv manager, mindst én tildelt Tab, Location Read (også inkluderet i Write/Create) og adgang til det aktuelle site, bank eller lokation. Lokationsadgang giver kun de tildelte lokationer. Slettede lokationer følger RetentionDays. 400: ugyldig KID eller forkert site; 401: log ind igen; 403: manglende adgang; 503: prøv senere. Data caches i op til 60 sekunder, mens adgang kontrolleres ved hvert kald. Listen sorteres efter lokationsnummer uden paginering. Kun lokationer med Name, Icon eller Deleted i Log24 kan findes. Manglende eller ugyldigt ikon giver house. Brug kid som lokationens ID og name som visningsnavn.
Lokationsoverblik og units
GET /api/v1/locations/{locationKid}/units, operationId GetLocationUnits. Svaret er {location:{kid,name,icon},items:[{kid,name,icon}]}. Brug en kanonisk lokations-KID fra bankens lokationsliste eller en beboers locations; sidstnævnte indeholder nu også lokationens name.
const response = await fetch(`${api}/api/v1/locations/${encodeURIComponent(locationKid)}/units`, {
headers: { Authorization: `Bearer ${token}` }
});
if (!response.ok) throw new Error(`Unit request failed: ${response.status}`);
const { location, items } = await response.json();Kræver aktiv manager, mindst én Tab, Location Read og Unit Read (Write/Create inkluderer Read), samt adgang til sitet og banken eller netop denne lokation. Adgang genkontrolleres ved hvert kald. Lokationens og unitternes Deleted følger RetentionDays; manglende Deleted betyder ikke slettet. 400: forkert KID/site; 401: log ind igen; 403: manglende rettighed; 404: lokationen mangler eller er ikke længere synlig; 503: prøv senere. Der returneres højst 255 units, sorteret efter unitnummer, uden paginering. Tom items er et gyldigt resultat.
Data fra Log24 caches i op til ét minut. Kun objekter med Name, Icon eller Deleted kan findes. Manglende navn er tomt, manglende/ugyldigt ikon giver house. Web bruger /locations/{locationKid} som delbart link. Genveje i arbejdsområdet gemmes kun pr. manager og browserfane og giver aldrig rettigheder; krydset fjerner kun genvejen.
Unit-overblik bruger det delbare link /units/{unitKid}. Portalen genbruger GetLocationUnits og vælger den præcise unit-KID blandt API-autoriserede resultater. En manglende eller ikke-synlig unit giver ingen detaljer. Der er endnu ingen yderligere unitfunktioner. Arbejdsområdets unit-genveje gemmes under lokationen; krydset fjerner kun genvejen og går tilbage til lokationen, hvis unit var åben.
Sprog i unitnavne
Send Accept-Language: da-DK på hvert API-kald. Sproget bindes ikke til login eller token. Unitnavne som [455] 1 får den kendte eLocalization-pladsholder erstattet af den fælles oversættelse; øvrig tekst bevares. Ukendte id-numre forbliver uændrede. Content-Language angiver det valgte sprog. Samme ti sprog som portalen understøttes; regionale varianter accepteres, no/nn bruger norsk bokmål og pt-BR bruger pt-PT. Manglende, ugyldigt eller ikke-understøttet sprog giver en-GB. Prioriteter q respekteres, q=0 fravælges. Rå data caches før oversættelse, så sprog ikke blandes mellem brugere og ikke giver ekstra SQL.
const response = await fetch(`${api}/api/v1/locations/${locationKid}/units`, { headers: { Authorization: `Bearer ${token}`, "Accept-Language": "da-DK" } });
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const overview = await response.json();Aktuel eCycle
GetLocationUnits returnerer nu cycle (stabilt eCycle-navn) og cycleText (Accept-Language) på hver enhed. Begge er null ved manglende eller ugyldig værdi. Nyeste MS2000 fra eSetting.Cycle (1619, Settings) og eState.Cycle (20, States) vælges; ved samme tid vinder States. En ugyldig nyeste værdi erstattes aldrig af en ældre. Enhedsdata caches nu højst 10 sekunder; lokationsnavne og managerrettigheder stadig højst ét minut. SQL er afgrænset til banken og lokationen for begge grene. Portalen opdaterer hvert 10. sekund, pauser i skjulte faner, undgår samtidige kald og skjuler gamle detaljer ved fejl. Eksterne klienter kan gentage samme GET med samme bearer-token og Accept-Language hvert 10. sekund.
Afregning: visning, historik og downloads
Alle kald kræver Authorization: Bearer TOKEN, fanen Settlement2, læserettighed til bank og brugere samt adgang til hele banken. Adgang til enkelte lokationer giver ikke adgang til bankens samlede afregning. API'et kontrollerer aktuelle rettigheder ved hvert kald; manageroplysninger caches højst ét minut. Afregning bliver aldrig afsluttet, fortrudt eller ændret af disse GET-kald.
| Operation | GET-sti |
|---|---|
| GetBankSettlements | /api/v1/banks/{bankKid}/settlements?beforePeriod=123 |
| GetBankSettlementPeriod | /api/v1/banks/{bankKid}/settlements/{period} |
| DownloadBankSettlement | /api/v1/banks/{bankKid}/settlements/{period}/download?format=XLS |
Udelad beforePeriod ved første historikkald. Svaret indeholder op til 25 afsluttede perioder, nextSettlement og nextBeforePeriod. Send næste markør uændret; null betyder slut. Ukendte datoer og værdier er null. Datoer er UTC. Periode 0 er den igangværende, foreløbige periode og findes kun via detalje- og downloadkald. Den kan ændre sig frem til afregning.
Detaljer indeholder sourceEntries, includedEntries, groups og formats. Hver gruppe har group, currency, entries og amountMinor. Summen er fortegnet fra databasen i mindsteenheder, ikke et formatteret valutabeløb. Beløb i forskellige valutaer lægges aldrig sammen. Historikkens registrerede sum kan afvige fra eksporten.
Elforbrug med ChargePoint_58/TimeNew udelades; kontantbanker udelader også Month og Transfer. Grupper vælges i rækkefølgen ETest, EInstaller, EGuest, bankens nummermasker (U), EDate og LR. Nummermasker bruger % for flere tegn og _ for ét tegn. Gyldige ældre posteringer med typen Unknown medtages med deres registrerede beløb. Brugernes aktuelle nummer, navn, brikker og attributter anvendes, så en genhentet historisk fil er ikke nødvendigvis identisk med den oprindelige. Afregning er undtaget fra RetentionDays: slettede brugere indgår også i periodens detaljer og downloads uanset sletningens alder. De almindelige manager-, fane-, bank- og læserettigheder kontrolleres stadig.
Download er en ZIP-fil med én fil per gruppe og valuta samt manifest.json til afstemning. En tom periode indeholder kun manifestet. Tekstformater kan udelade grupper uden eksportérbare beløb; gruppernes summer fremgår stadig af manifestet. XLS giver rigtige .xlsx-filer med Number, Amount og UserId efter eksportformatets konvention; UserId i dette kompatibilitetsformat er numerisk, mens HTTP-kontrakten bruger KID'er. De øvrige formater er UTF-8-tekst med CRLF. Et Excel-beløb beholder databasens fortegn; eksempelvis NAVISION vender fortegnet.
Tilgængelige formater: XLS, ATB, BL, DEAS, FRUEHØJGAARD, HEIMSTADEN, LEJERBO, MD90_1, MD90_3, MD90_3_minus, MD90_3_plus, MD90_3_AABKBH og NAVISION. MD90_3 er kun defineret for bank 1001 og 1068. NIRAS og ROBERT er obsolete. HUMAN, KMD, LYKKEBO og MD90 tilbydes ikke, da den undersøgte fælles eksportkode ikke har en implementeret eksport for dem. Formatnavne er case-sensitive; brug listen fra detaljesvaret.
const headers = { Authorization: `Bearer ${token}` };
const base = `/api/v1/banks/${encodeURIComponent(bankKid)}/settlements`;
const details = await fetch(`${base}/12`, { headers });
if (!details.ok) throw new Error(`HTTP ${details.status}`);
const period = await details.json();
const download = await fetch(`${base}/12/download?format=XLS`, { headers });
if (!download.ok) throw new Error(`HTTP ${download.status}`);
const url = URL.createObjectURL(await download.blob());
const link = document.createElement('a');
link.href = url; link.download = 'afregning-12.zip'; link.click();
setTimeout(() => URL.revokeObjectURL(url), 60000);
Eksemplet forudsætter samme origin; eksterne browserportaler bruger API'ets fulde baseadresse og en tilladt CORS-origin. 400 betyder ugyldig KID/periode/format, 401 kræver nyt login, 403 betyder manglende rettigheder, 404 betyder ukendt afsluttet periode, 422 betyder data, der ikke kan eksporteres sikkert, og 503 betyder midlertidigt utilgængelige data. Ved 422 kan årsagen være ugyldig transaktionskode, ugyldigt nummer/valuta, flere brugere med samme eksportnummer, feltoverskridelse eller mere end 100.000 posteringer/10.000 brugere. Ingen delvise filer leveres. Ret data/format frem for at gentage 422. Ved 503 vent før nyt forsøg.
Historik og periodedata caches højst ét minut med samling af samtidige opslag. Detaljer hentes først, når en periode vælges. Der udføres ingen baggrundsforespørgsler og ingen MySQL-skrivninger. Den gamle sides afregningsparathed og automatiske jobs er ikke flyttet; dette API påstår ikke, at en bank er klar til at blive afsluttet.
Disp73: Offentligt kort med køb
GET /api/v1/public/displays/disp73 · operation GetPublicDisp73. Kaldet kræver hverken login eller token. Det viser køb på tværs af alle banker på det aktuelle API-site, uafhængigt af managerrettigheder. Andre beskyttede bankkald kræver stadig login og rettigheder.
const response = await fetch('https://api.team.kombine.technology/api/v1/public/displays/disp73');
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const sample = await response.json();
for (const purchase of sample.items) {
// Gem purchase.id, så samme køb ikke animeres igen ved næste kald.
showCoin(purchase.latitude, purchase.longitude, purchase.amount, purchase.currency);
}
showCoin er din egen kortfunktion. JavaScript-klienten tilbyder også client.getDisp73() uden login. items indeholder {id, latitude, longitude, amount, currency}. id er et uigennemsigtigt event-ID til at genkende gentagne køb, ikke et objekt-ID til andre API-kald. Koordinater er bredde-/længdegrader; beløbet er positivt i valutaens hovedenhed. Valuta kan være null. Valutaer omregnes ikke.
Fremtidige terminaltidsstempler i Log1Hour medtages som i den gamle Purchase2. Svaret viser køb fra den seneste time. Hele timen genlæses, så forsinkede køb også medtages. Brug id til at undgå gentagne animationer ved efterfølgende opslag. Negative køb uden overførsler medtages, og poster uden gyldige koordinater springes over. Enhedens koordinater bruges først, ellers lokationens. Bruger-, bank- og enheds-ID, navne, brikker og transaktionstekst returneres ikke. Kaldet accepterer ingen tenant-, bank-, periode- eller limit-parametre.
Alle besøgende deler en cache på 10 sekunder per API-instans. Hent tidligst igen efter refreshAfterSeconds (10); undgå parallelle kald og stop opdatering i skjulte faner eller ved pause. Gem event-ID’er i mindst to minutter for at undgå gentagne mønter. measuredAtUtc er måletidspunktet; vis det med browserens lokale dato/tid. Tom items betyder ingen køb med koordinater i prøven. HTTP 503 betyder utilgængelige data, ikke nul køb; vent mindst 30 sekunder som angivet i Retry-After. Eksterne browserklienter skal have en tilladt CORS-origin.
Portalen viser kortet uden login på /disp73 og under Disp73-fanen. Kortet kan flyttes og zoomes; pauseknappen stopper opdatering, og vis-alle-knappen tilpasser udsnittet. Reduceret bevægelse i browseren slår faldanimationen fra.