Exsitec Data Link

Rå ↓ — Rå Markdown til AI-assistenter

Exsitec Data Link — Brug

Exsitec Data Link er en lille Windows-companion, der lader et lokalt program — et Excel-regneark, et script eller dit eget værktøj — køre Visma Business NXT GraphQL queries og mutations uden selv at håndtere Visma-login eller token. Den logger på Business NXT for dig og stiller en styret GraphQL-gateway på din egen maskine til rådighed (localhost): Du sender et GraphQL-dokument, Data Link kontrollerer dine Data Link-rettigheder for hver virksomhed, dokumentet berører, og videresender det til Business NXT under dit eget Visma-login. Svaret fra Business NXT kommer uændret tilbage.

Læser du dette med en AI-assistent? Denne side er den komplette brugsreference. Du kan indsætte den i din assistent eller give den den rå Markdown på /docs/usage.md?lang=da (samme indhold, uden styling). Bed den skrive forespørgslerne i det sprog, du vælger — alt, hvad den behøver (endpoints, headere, rettighedsregler, request- og response-formater samt fejlformatet), står nedenfor. Til selve Business NXT-skemaet (tabeller, felter, filtre) skal du pege den mod Vismas Business NXT GraphQL-dokumentation eller bede den køre en introspection query gennem gatewayen.


1. Kom hurtigt i gang

  1. Installér og log på. Installér Data Link, højreklik derefter på dens bakkeikon (nederst til højre, ved uret) → Sign in. Din browser åbner Visma Connect; log på dér.

  2. Find port og nøgle. Læs %LOCALAPPDATA%\Exsitec\DataLink\endpoint.json — den indeholder loopback-port og en key, der gælder for den aktuelle opstart.

  3. Sig hej. GET http://127.0.0.1:{port}/v1/status med headeren X-DataLink-Key: {key}. Du får versionen og om du er logget på.

  4. Vælg en virksomhed. GET /v1/companies viser de virksomheder, du har adgang til, samt hvad din Data Link-adgang og dine tilladelser lader dig gøre i hver af dem.

  5. Kør GraphQL. POST /v1/nxt/graphql med en standard GraphQL-body:

    { "query": "{ useCompany(no: 4926238) { generalLedgerAccount(first: 5) { items { accountNo name } } } }" }
    

    Svaret er Business NXTs eget { "data": …, "errors": … }.


2. Sådan kører den

Hvor ting ligger

Hvad Hvor
Discovery-fil (port + nøgle) %LOCALAPPDATA%\Exsitec\DataLink\endpoint.json — kun læsbar for dig.
Logs %LOCALAPPDATA%\Exsitec\DataLink\logs\ (bakke → Open logs folder). Logs indeholder aldrig GraphQL-dokumenter, beløb, nøgler eller tokens.
Login-session session.dat i samme mappe, krypteret til din Windows-bruger.
Selve appen %LOCALAPPDATA%\Exsitec.DataLink\ (brugerinstallation, der opdaterer sig selv).

3. Kommunikation med det lokale API

Discovery — find port og nøgle

Companionen vælger en ledig loopback-port ved opstart og skriver en lille discovery-fil, så betroede lokale kaldere kan finde den:

%LOCALAPPDATA%\Exsitec\DataLink\endpoint.json
{
  "port": 51234,
  "key": "b3d1…a9f0",
  "instanceId": "3f2a…",
  "processId": 18244,
  "protocol": "v1",
  "version": "2.0.0",
  "startedUtc": "2026-10-07T07:15:00.0000000+00:00"
}

Base URL og versionering

http://127.0.0.1:{port}/v1/…

Alle endpoints ligger under præfikset /v1 (protocol-feltet i discovery-filen); GraphQL-gatewayen er /v1/nxt/graphql. Bind til 127.0.0.1 (loopback) — companionen lytter kun dér.

Påkrævede request-headere

Header Hvornår Værdi
X-DataLink-Key Hver request key fra endpoint.json.
Content-Type: application/json Requests med JSON-body Send bodyen som UTF-8.

Der er ingen virksomhedsheader: Virksomheden navngives inde i GraphQL-dokumentet.

Svarheadere

Header Betydning
X-DataLink-Instance Companionens instanceId for denne kørsel.

Genstartssignal. Hvis værdien af X-DataLink-Instance ændres mellem kald, har companionen genstartet. Læs endpoint.json igen — både port og nøgle kan være ændret.

Timeouts

Sikkerhedsbegrænsninger (derfor afvises browser-fetch)

Companionen håndhæver en loopback-tillidsgrænse:


4. Endpoint-reference

Hver request kræver X-DataLink-Key. Response-bodies fra selve Data Link er JSON med feltnavne i camelCase; POST /v1/nxt/graphql returnerer Business NXTs body uændret.

Metode Sti Formål
GET /v1/status Health, version og loginstatus.
POST /v1/auth/login Interaktivt browserlogin.
POST /v1/auth/logout Afslut Business NXT-sessionen.
GET /v1/companies Virksomheder, loginet har adgang til, med dine rettigheder i hver.
POST /v1/nxt/graphql Enhver Business NXT GraphQL-query eller mutation, rettighedskontrolleret.

GET /v1/status

Health og loginstatus. Den virker, mens du er logget ud.

{
  "status": "ok",
  "instanceId": "3f2a…",
  "protocol": "v1",
  "version": "2.0.0",
  "provider": { "id": "business-nxt", "authenticated": true },
  "startedUtc": "2026-10-07T07:15:00+00:00"
}

POST /v1/auth/login

Starter det interaktive browserlogin og returnerer, når det er færdigt. Ingen body. Den åbner altid browseren, også når du allerede er logget på — tjek GET /v1/status først, hvis du kun vil logge på ved behov.

{ "authenticated": true }

Hvis browserforløbet ikke fuldføres inden for 5 minutter, fejler kaldet med 503 unavailable (retryable: true); et login, som Visma Connect afviser, returnerer 401 unauthorized.

POST /v1/auth/logout

Afslutter Business NXT-sessionen. Returnerer { "authenticated": false }.

GET /v1/companies

De virksomheder, det aktuelle login har adgang til (Business NXTs availableCompanies), hver med sin tenant (den Visma.net-kunde, den hører til) og den Data Link-adgang og de tilladelser, der gælder dér — så du kan slå et virksomhedsnavn op til dets nummer og se, hvad du må gøre, før du forsøger.

{
  "available": [
    { "id": "4926238", "name": "Exsitec BNXT Demo",         "tenantId": "4926230", "canRead": true, "canWrite": false, "canDelete": false },
    { "id": "6307615", "name": "Demo - Junge Byg Aps 9999", "tenantId": "2728812", "canRead": true, "canWrite": true,  "canDelete": false }
  ]
}

En virksomhed vist med canRead: false er en, dit Visma-login kan se, men som Data Link ikke åbner for dig (se afsnit 5).

POST /v1/nxt/graphql — gatewayen

Kører enhver Business NXT GraphQL-query eller mutation. Bodyen er standard GraphQL-over-HTTP:

{
  "query": "query Accounts($company: Int!) { useCompany(no: $company) { generalLedgerAccount(first: 5) { items { accountNo name } } } }",
  "variables": { "company": 4926238 },
  "operationName": "Accounts"
}
Felt Påkrævet Betydning
query ja GraphQL-dokumentet (streng).
variables nej Et JSON-objekt med variabelværdier.
operationName nej Hvilken operation der skal køres, når dokumentet har flere.
extensions nej Standard GraphQL-udvidelsesdata, videresendt uændret. Rettighedskontrollen læser dem ikke.

Det sker der:

  1. Data Link parser dokumentet og finder ud af, hvilke virksomheder det læser, skriver eller sletter i (afsnit 6).
  2. Den kontrollerer din Data Link-adgang og dine tilladelser for hver af dem. Hvis noget ikke er tilladt, afvises hele dokumentet, og intet når Business NXT.
  3. Ellers videresender den din request-body uændret til Business NXT under dit Visma-login og returnerer Business NXTs HTTP-status og body ordret — inklusiv Business NXTs egne errors og extensions (for eksempel extensions.vbnxt-trace-id).
{
  "data": {
    "useCompany": {
      "generalLedgerAccount": {
        "items": [ { "accountNo": 1010, "name": "Varesalg DK" }, { "accountNo": 1020, "name": "Anden omsætning" } ]
      }
    }
  },
  "extensions": { "vbnxt-trace-id": "…" }
}

Data Link fornyer selv dit Visma-token, og når Business NXT svarer 429 Too Many Requests, venter den og prøver igen — begge dele er sikkert, fordi requesten ikke blev kørt. Den prøver aldrig andet igen, så en mutation kan aldrig køre to gange; en 5xx fra Business NXT sendes tilbage til dig, som den er.


Hvad du må gøre gennem Data Link, administreres af Exsitec i NxtPlatform admin. Den gamle Config API-portal til tildelinger er væk; dokumentations- og downloadhosten giver ikke adgang.

Hvad Tildelt Tillader
Data Link Access Pr. tenant (en Visma.net-kunde) gennem Data Link-modulet — for alle brugere eller valgte grupper, med tilsidesættelse pr. bruger. Læsning af enhver virksomhed i den tenant (canRead). Uden den afvises alt på tenantens virksomheder, også læsninger.
Write-tilladelse Gennem NxtPlatform-roller. Mutations, der opretter, opdaterer, processerer eller rapporterer (*_create, *_update, *_processings, *_reports, edit-cache-styring) — på tenants, hvor du har Data Link Access (canWrite).
Delete-tilladelse Gennem NxtPlatform-roller. Mutations, der sletter (*_delete) — på tenants, hvor du har Data Link Access (canDelete). Sletning kræver Delete, ikke Write.

Data Link begrænser kun det, din egen Visma-bruger må gøre — den giver aldrig adgang, som Visma ikke ville give. En virksomhed uden for dine availableCompanies afvises, selv hvis du har adgang til dens tenant.

Når du ikke har Write-tilladelse noget sted, beder Data Link også Visma om et skrivebeskyttet login, næste gang du logger på, så Business NXT selv også afviser mutations.

Din adgang og dine tilladelser hentes fra NxtPlatform, når du logger på, opdateres med få minutters mellemrum og holdes kun i hukommelsen. Hvis NxtPlatform ikke kan nås, gælder det seneste svar i en kort grace-periode; derefter — eller hvis Data Link aldrig har nået NxtPlatform, siden den startede — afviser gatewayen med 503 unavailable (retryable: true) i stedet for at køre uden kontrol.


6. Sådan læser rettighedskontrollen et dokument

Kontrollen arbejder på det parsede dokument, aldrig på teksten, så aliases, fragments og variables kan ikke skjule noget. Den er bevidst streng:

Hver virksomhedsspecifik læsning eller skrivning ligger under en root useCompany(no: …). no er virksomhedsnummeret fra GET /v1/companies — en literal, en variable eller en variable-default:

query Projects($company: Int!) {
  useCompany(no: $company) {
    orgUnit2(filter: { orgUnit2No: { _eq: 2130 } }) { items { orgUnit2No name } }
  }
}

(Business NXTs organisatoriske enheder navngives pr. virksomhed; i Demo - Junge Byg Aps 9999 er projekter orgUnit2.)

Hvad hver del af et dokument kræver

I dokumentet Kræver
query { useCompany(no: N) { … } } Read på virksomhed Ns tenant.
mutation { useCompany(no: N) { x_create / x_update / x_processings / x_reports / finishEditCache … } } Write på Ns tenant.
mutation { useCompany(no: N) { x_delete … } } Delete på Ns tenant.
query { useCustomer(no: T) { … } } Read på tenant T.
mutation { useCustomer(…) } Afvises altid — ændringer på kundeniveau (brugere, virksomheder) sker ikke gennem Data Link.
mutation { asyncQuery(query: "…", args: {…}) } Det, det indlejrede dokument kræver, kontrolleret efter samme regler.
availableCompanies, availableCustomers, useModel, api, asyncRequests, asyncResult, asyncQuery_delete, introspection (__schema, __type) Kun login.
Ethvert andet root-felt eller en subscription Afvises (403 forbidden).

Sikker skrivning

Business NXT har ingen transaktioner på tværs af tabeller. To vaner gør skrivning forudsigelig:


7. Fejl

Der er to slags fejl, og begge bruger GraphQLs error-shape.

Business NXTs egne fejl — en GraphQL-fejl, en værdi Business NXT afviser, en rate limit — kommer tilbage præcis som Business NXT sendte dem: HTTP-status og bodyen { "data": …, "errors": [ … ] }.

Afvisninger fra selve Data Link (requesten nåede aldrig Business NXT) har extensions.code:

{
  "errors": [
    {
      "message": "You have no Data Link Write permission for company 'Exsitec BNXT Demo' (4926238).",
      "extensions": { "code": "forbidden", "retryable": false, "instanceId": "3f2a…", "company": "4926238" }
    }
  ]
}
code HTTP Betydning / hvad du skal gøre
invalid_request 400 Bodyen er ikke JSON, mangler query, har andre medlemmer end query/variables/operationName/extensions eller gentagne property names (også når de kun adskiller sig i store/små bogstaver), variables er ikke et objekt, dokumentet kan ikke parses, eller et virksomhedsnummer kan ikke opløses. Ret og send igen.
unauthorized 401 Manglende/ugyldig nøgle, ikke logget på, eller Visma afviste login. Læs endpoint.json igen; log på.
forbidden 403 Din Data Link-adgang eller dine tilladelser tillader ikke dette på en virksomhed (extensions.company angiver den), virksomheden er ikke tilgængelig for dig, eller dokumentet bruger en afvist root (useCustomer-mutation, ukendt root, subscription). Også cross-origin-/host-blokeringer.
unavailable 503 Dine rettigheder kunne ikke hentes (retryable: true), eller Data Link er optaget. Prøv igen om lidt.
internal_error 500 Uventet. Tjek logmappen (bakke → Open logs folder).

GET /v1/status, /v1/auth/* og GET /v1/companies rapporterer deres fejl i Data Links almindelige envelope i stedet:

{ "code": "unauthorized", "message": "…", "retryable": false, "instanceId": "3f2a…" }

En ukendt sti får en ren 404.


8. Forholdet til Business NXT GraphQL API

Data Link er Business NXTs GraphQL API, tilgået gennem din egen maskine:


9. Brug fra Excel

Download og importér de to VBA-moduler nedenfor (Alt+F11 -> File -> Import File...). De er standardmoduler og bruger kun late binding, så der er ikke behov for ændringer i Tools -> References.

Fil Hvad det er
ExsitecDataLink.bas Det faste SDK: autostart, discovery, login, GraphQL, JSON, fejl og output til regneark.
ExsitecDataLinkCustom.bas Din workbook-skabelon: COMPANY_NO og eksempelmakroer til knapper. Tilpas denne fil pr. kunde/workbook.

Offentligt VBA API

API Formål
NxtQuery(gql, [vars]) As Object Sender en GraphQL-query eller mutation til POST /v1/nxt/graphql og returnerer data-dictionaryen. Hvis dokumentet bruger $company, og vars ikke har company, tilføjer SDKet COMPANY_NO.
NxtVars(name, value, ...) As Object Bygger en variables-dictionary. Eksempel: NxtVars("company", 4926238, "first", 20).
NxtItems(data, path) As Collection Går gennem en dot-noteret sti som useCompany.generalLedgerAccount og returnerer dens items-collection. items: null bliver en tom collection.
WriteRows(items, target, [columns], [includeHeader]) As Range Skriver rækker til Excel i én blok. Nested objects udvides ét niveau (a.b), ISO-datoer bliver Excel-datoer, null bliver tomt, og tekst, der ligner formler, forbliver tekst.
ShowNxtError() Viser Err.Description i en brugervenlig beskedboks. Brug den i error handlers.
NxtUseEndpointFile(path) Avanceret/test hook til en ikke-standard discovery-fil.
NxtUseLanguage(languageCode) Avanceret/test hook, der tilsidesætter SDKets beskedsprog (en, da, sv, nb).
NxtUseStartPaths(primaryExe, fallbackExe) Avanceret/test hook til ikke-standard stier til Data Link-eksekverbare filer.

Mønster for knapmakro

Læg virksomhedsspecifikke indstillinger og knapmakroer i ExsitecDataLinkCustom.bas:

Public Const COMPANY_NO As Long = 4926238

Public Sub ListAccounts()
    On Error GoTo Failed
    Dim data As Object
    Set data = NxtQuery("query Accounts($company: Int!) { useCompany(no: $company) { generalLedgerAccount(first: 20) { items { accountNo name } } } }")
    WriteRows NxtItems(data, "useCompany.generalLedgerAccount"), ActiveSheet.Range("A1"), Array("accountNo", "name")
    Exit Sub
Failed:
    ShowNxtError
End Sub

Til mutations kalder du samme NxtQuery-funktion med et mutation-dokument. SDKet prøver aldrig mutations igen efter portændring eller transportfejl.

Autostart og login

SDKet læser %LOCALAPPDATA%\Exsitec\DataLink\endpoint.json. Hvis filen mangler, eller /v1/status ikke svarer, starter det %LOCALAPPDATA%\Exsitec.DataLink\Exsitec Data Link.exe (eller current\DesktopDataLink.Host.exe) og venter op til 30 sekunder.

Før hvert kald tjekker det /v1/status. Hvis du er logget ud, fortæller Excel, at browseren åbner, kalder /v1/auth/login og rejser derefter en fejl, der beder dig køre handlingen igen, når login er fuldført. Den oprindelige GraphQL-request køres ikke automatisk efter login.

VBA-fejlnumre

Konstant Betydning
NXT_ERR_NOT_RUNNING Data Link er ikke installeret, kunne ikke startes eller svarede aldrig.
NXT_ERR_NOT_SIGNED_IN Du er logget ud, annullerede login, eller login kræver, at handlingen køres igen.
NXT_ERR_FORBIDDEN Data Link Access/Permissions forbyder requesten eller virksomheden.
NXT_ERR_INVALID GraphQL-requesten er forkert formet eller ikke tilladt af gatewayen.
NXT_ERR_NXT Business NXT returnerede GraphQL-fejl; Err.Description er den første Business NXT-meddelelse.
NXT_ERR_UNAVAILABLE Data Link, Business NXT eller rettighedstjenesten er midlertidigt utilgængelig.
NXT_ERR_OTHER Enhver anden response uden succes.

Beskeder bruger Data Link-bakkens sprogindstilling (ui-settings.json) for engelsk, dansk, svensk og norsk, med engelsk som standard.


10. Eksempler i andre sprog

PowerShell

# 1. Discover the running companion.
$ep   = Get-Content "$env:LOCALAPPDATA\Exsitec\DataLink\endpoint.json" | ConvertFrom-Json
$base = "http://127.0.0.1:$($ep.port)/v1"
$hdr  = @{ "X-DataLink-Key" = $ep.key }

# 2. Check status / sign-in.
Invoke-RestMethod "$base/status" -Headers $hdr

# 3. Resolve a company name to its number, and see your rights there.
$companies = (Invoke-RestMethod "$base/companies" -Headers $hdr).available
$company   = $companies | Where-Object { $_.name -eq "Exsitec BNXT Demo" }

# 4. Run GraphQL.
$body = @{
    query     = 'query A($c: Int!) { useCompany(no: $c) { generalLedgerAccount(first: 5) { items { accountNo name } } } }'
    variables = @{ c = [int]$company.id }
} | ConvertTo-Json -Depth 5

$result = Invoke-RestMethod "$base/nxt/graphql" -Method Post -Headers $hdr `
    -ContentType "application/json" -Body $body
$result.data.useCompany.generalLedgerAccount.items

Python

Kun standardbibliotek:

import json, os, urllib.request

path = os.path.join(os.environ["LOCALAPPDATA"], "Exsitec", "DataLink", "endpoint.json")
with open(path, encoding="utf-8-sig") as f:
    ep = json.load(f)
base = f"http://127.0.0.1:{ep['port']}/v1"

def call(method, path, body=None):
    headers = {"X-DataLink-Key": ep["key"]}
    data = None
    if body is not None:
        data = json.dumps(body).encode("utf-8")
        headers["Content-Type"] = "application/json"
    request = urllib.request.Request(base + path, data=data, headers=headers, method=method)
    with urllib.request.urlopen(request, timeout=300) as response:   # HTTPError carries the GraphQL errors
        return json.load(response)

def graphql(query, **variables):
    return call("POST", "/nxt/graphql", {"query": query, "variables": variables})

companies = call("GET", "/companies")["available"]
junge = next(c for c in companies if c["name"] == "Demo - Junge Byg Aps 9999")

result = graphql(
    "query P($c: Int!, $p: Int!) { useCompany(no: $c) { orgUnit2(filter: { orgUnit2No: { _eq: $p } }) { items { orgUnit2No name } } } }",
    c=int(junge["id"]), p=2130)
print(result["data"]["useCompany"]["orgUnit2"]["items"])

11. Fejlfinding

Symptom Sandsynlig årsag Hvad du skal gøre
Ingen endpoint.json eller VBA NXT_ERR_NOT_RUNNING Data Link er ikke installeret eller svarede ikke. VBA SDKet starter den automatisk; hvis det fejler, så installér den fra dokumentations-/downloadsiden.
Forbindelse afvist, efter det virkede før Data Link genstartede eller afsluttede (f.eks. efter en opdatering): ny port og nøgle. Læs endpoint.json igen.
401 "A valid connector key is required." Manglende eller forældet nøgle. Læs endpoint.json igen — nøglen ændres ved hver start.
401 "Not signed in to Business NXT…" Ikke logget på, eller sessionen sluttede. Bakke → Sign in (eller POST /v1/auth/login).
403 "Cross-origin requests are not permitted." Kaldet kom fra browser-JavaScript. Kald fra et lokalt program eller script i stedet.
403 "You have no Data Link Access to …" Du har ikke Data Link Access på den virksomheds tenant. Bed din Exsitec-kontakt om Data Link-adgang til den tenant.
403 "You have no Data Link Write / Delete permission…" Dine NxtPlatform-roller mangler den tilladelse (canWrite / canDelete). Spørg din Exsitec-kontakt; tjek GET /v1/companies.
403 "Company … is not available to the signed‑in user." Din Visma-bruger kan ikke se den virksomhed, eller nummeret er tastet forkert. Tjek GET /v1/companies; log ud og ind med den rigtige Visma-bruger.
400 "…'no' argument must resolve to an integer." useCompany uden nummer eller en variable, du ikke sendte. Send virksomhedsnummeret som en Int literal eller variable.
503 "Data Link rights could not be fetched…" NxtPlatform kan ikke nås. Prøv igen om lidt.
503 "Sign-in timed out…" Browserlogin blev ikke afsluttet inden for 5 minutter. Prøv igen og fuldfør det i browseren.
Excel viser "Not Responding" under login /v1/auth/login venter på browseren. Afslut login i browseren; kør derefter Excel-handlingen igen.

Sidder du stadig fast? Bakke → Open logs folder og send den nyeste logfil til din Exsitec-kontakt — den indeholder ingen GraphQL-dokumenter, beløb, nøgler eller tokens.


12. Ordliste

Begreb Betydning
Data Link (companion) Bakkeappen på din pc, der logger på Business NXT og betjener den lokale gateway.
NXT Gateway POST /v1/nxt/graphql: Business NXT GraphQL, rettighedskontrolleret og videresendt under dit login.
Rettighedskontrol Gatewayens kontrol af et parset GraphQL-dokument mod din Data Link Access og dine Permissions, alt eller intet.
Data Link Access Din ret til overhovedet at bruge Data Link på en tenants virksomheder (canRead), tildelt i NxtPlatform admins Data Link-modul.
Data Link Permission Write eller Delete (canWrite / canDelete), tildelt gennem NxtPlatform-roller; den gælder kun på tenants, hvor du har Data Link Access.
Tenant En Visma.net-kunde; Data Link Access tildeles pr. tenant.
Virksomhed En Business NXT-virksomhed, identificeret ved sit nummer og navngivet i hvert dokument med useCompany(no: …).
Discovery-fil endpoint.json: hvor den kørende Data Link offentliggør sin port, nøgle og instans-id.
Nøgle Hemmeligheden pr. opstart, som hver request skal have med; den ændres ved hver start.
Instans-id Identificerer én kørsel af Data Link; en ny værdi betyder, at den genstartede.

Dette dokument beskriver det lokale v1-API. Companionen rapporterer sin kørende version i GET /v1/status og i bakkemenuen.

↑ Top