Skip to main content

API og autentisering

API-et ligger på https://api.utlegg.app. Den interaktive referansen finner du på api.utlegg.app/api-docs (Swagger UI), og OpenAPI-spesifikasjonen som JSON på api.utlegg.app/api-docs-json.

Kontrakt (Prefer: contract=next)​

OBS

Bruk headeren Prefer: contract=next i alle API-kall, da dokumentasjonen forutsetter dette. Uten denne svarer API-et i et eldre format som ikke stemmer med eksemplene.

Header-format​

Alle autentiserte kall sender token i Authorization-headeren:

Authorization: Bearer <token>
Prefer: contract=next

Tokens har prefiks som forteller hva de er:

PrefiksTypeBrukes for
ua_Personal Access Token (PAT)Personlige integrasjoner og utviklerbruk
uas_Service Access Token (SAT)Maskin-til-maskin (organisasjon eller globalt)
(JWT)Bruker-sessionWeb/mobil etter ordinær innlogging

API-et identifiserer token-type ut fra prefikset; du trenger ikke spesifisere dette eksplisitt.

Personal Access Tokens (PAT)​

En PAT er knyttet til din egen brukerkonto og har samme rettigheter som deg selv i de organisasjonene du tilhører. Bruk den til scripts, ad hoc-integrasjoner og utviklertesting.

Lag en PAT i webdashbordet​

  1. Logg inn på dashbordet.
  2. Gå til Innstillinger → Utvikler → Personal Access Tokens.
  3. Klikk Lag ny, gi den et navn og velg varighet.
  4. Kopier tokenen umiddelbart – den vises kun én gang.

Lag en PAT via API-et​

curl -X POST https://api.utlegg.app/users/pat \
-H "Authorization: Bearer <din-eksisterende-token>" \
-H "Prefer: contract=next" \
-H "Content-Type: application/json" \
-d '{"name": "min-integrasjon", "expiresAt": "2026-12-31T00:00:00Z"}'

Endepunktet gir en 201-respons med et token-felt. Tokenen utløper som standard etter 30 dager hvis du ikke sender expiresAt.

Andre PAT-endepunkter:

  • GET /users/pat – list dine egne PATs
  • DELETE /users/pat/:id – tilbakekall en PAT

Listen inkluderer lastUsedAt – tidspunktet for siste vellykkede autentisering med tokenen, oppdatert med inntil 15 minutters forsinkelse. Verdien er null for tokens som ikke er brukt siden feltet ble innført.

Sikkerhetsregler​

  • Lagre PAT som en hemmelighet (env var, secret store) – aldri i kildekode eller logger.
  • Sett alltid expiresAt der det er praktisk.
  • Tilbakekall ubrukte tokens – bruk lastUsedAt for å finne dem.
  • En PAT mister tilgang umiddelbart hvis brukeren deaktiveres eller mister sin organisasjonsrolle.

Service Access Tokens (SAT)​

En SAT er en maskin-til-maskin-token knyttet til en service account i en organisasjon (eller globalt for partnere). Den brukes når en integrasjon skal kjøre uten en fysisk innlogget bruker. SAT-er har prefiks uas_.

Opprett og administrer en tjenestekonto i webdashbordet​

Organisasjons-administratorer oppretter og administrerer org-scopede tjenestekontoer selvbetjent:

  1. Logg inn på dashbordet.
  2. Gå til Innstillinger → Utvikler → Tjenestekontoer.
  3. Klikk Ny tjenestekonto, gi den et navn og velg tilgangsnivå (se under).
  4. Åpne tjenestekontoen og lag en tilgangstoken under Tilgangstokens (Nytt token).
  5. Kopier tokenen umiddelbart – den vises kun én gang.

Tjenestekontoen kan omdøpes eller slettes, og enkelttokens kan tilbakekalles uten å slette kontoen.

Globalt scope må fortsatt bestilles

Selvbetjeningen dekker org-scopede tjenestekontoer. En globalt-scopet SAT (for partnere/systemintegratorer med cross-tenant behov) opprettes ikke selvbetjent – ta kontakt på chat på utleggsappen.no og oppgi organisasjon, bruksområde, ønsket tilgang og en sikker leveringskanal for tokenen.

SAT-administrasjonsendepunktene under /organizations/:organizationId/service-accounts finnes, men er i dag interne og ikke med i den offentlige API-referansen – bruk dashbordet til å administrere org-scopede tjenestekontoer. Samme lastUsedAt-felt som for PAT-er finnes også på SAT-er, og kan brukes til å vurdere om en tjenestekonto fortsatt er i bruk.

Tilgangsnivå for org-scopede tjenestekontoer​

Hver tjenestekonto har ett av to grunnleggende tilgangsnivåer, valgt ved opprettelse og synlig i dashbordet:

NivåTilgang
AdminLes rapporter; les og oppdater fakturaer; full administrasjon av avdelinger, kategorier og prosjekter; les og administrer kontoer/organisasjon (inkl. provisjonering)
LesetilgangKun lesetilgang til rapporter, fakturaer, kategorier, avdelinger og prosjekter – ingen skrivetilgang, og ingen tilgang til kontoer/organisasjon

Utover grunnivået kan en organisasjons-admin tildele tjenestekontoen eksisterende egendefinerte roller fra tilgangspanelet i dashbordet, på samme måte som for brukere – nyttig for å gi presis tilgang uten å gå til Admin-nivået. Panelet viser også kontoens effektive tilgang (roller og tillatelsesnøkler).

SAT-er kan ikke opprette, endre, godkjenne eller slette rapporter, uansett tilgangsnivå eller tildelte roller. En SAT opptrer aldri som rapportinnleverer.

En globalt-scopet SAT kan lese brukere, kontoer og organisasjoner på tvers av tenants – brukes av partnere og systemintegratorer med cross-tenant behov.

Organisasjonskontekst​

De fleste ressurser er organisasjonsavgrenset, og endepunkter har formen:

/organizations/{organizationId}/...

For å finne dine organisasjons-IDer:

curl https://api.utlegg.app/users/me \
-H "Authorization: Bearer ua_..." \
-H "Prefer: contract=next"

Responsen inkluderer brukerens kontoer (accounts). Hver konto inkluderer organizationId og organisasjonen kontoen tilhører.

For SCIM brukes organisasjonens handle i stedet for ID:

/organizations/{organization_handle}/scim/Users

Du finner handle i URL-en på dashbordet (https://utlegg.app/{organization_handle}). SCIM-endepunktene autentiseres med en PAT fra en admin-bruker eller en SAT for en tjenestekonto med Admin-nivå – se SCIM-referansen.

Sjekke effektiv tilgang​

For å lese hvilke roller og tillatelsesnøkler du har:

GET /users/me/permissions

Legg til ?organizationId=<id eller handle> for å se din egen tilgang i en enkelt organisasjon. Responsen inneholder roles (liste med rolleobjekter, inkl. scope, scopeId og tier, systemrollen tilgangen bygger på) og permissions (liste med tillatelsesnøkler):

{
"roles": [
{
"id": "r1",
"name": "Approver",
"scope": "ORGANIZATION",
"scopeId": "org-abc",
"type": "CUSTOM",
"tier": null
}
],
"permissions": ["report.approve.manager-org", "report.read.manager-org"]
}

Bruk dette endepunktet til å implementere klient-side tilgangskontroll (can()-sjekker) i integrasjoner uten å hardkode rollenavn.

Endepunktet viser ikke tilgangen til en tjenestekonto, så kall med en SAT gir to tomme lister. Tjenestekontoens tilgang ser du i tilgangspanelet i dashbordet.

Standard responsformater​

Paginering​

Lister returneres som:

{
"items": [ ... ],
"hasMore": true,
"nextCursor": "eyJ2Ijo...",
"total": 137
}

items er sidens rader. hasMore er true om det finnes flere rader. Da er nextCursor med og kan sendes som cursor for å hente neste side. total er det totale antallet rader som matcher filteret og sendes bare når du ber om det med count=true. limit=0&count=true gir bare antallet.

Lister og filtrering​

Lister (GET /users, /expenses osv.) tar flate, typede query-parametere. Hvilke parametere en liste har, står på endepunktet i API-referansen; de er avledet av feltene i listeradene.

ParameterBeskrivelse
felt=verdiLik verdi. For id- og enum-felt kan du gjenta parameteren for «en av» (status=PENDING&status=APPROVED)
feltContains=tekstTekstfeltet inneholder teksten (skiller ikke mellom store og små bokstaver)
feltFrom, feltToIntervall for datoer, tidspunkt og beløp. From er inklusiv; To er inklusiv for beløp og eksklusiv for tidspunkt (beskrivelsen på parameteren sier hva som gjelder)
feltIsNulltrue eller false: feltet er eller er ikke tomt
sortEn av listens navngitte sorteringer
limitAntall rader per side
cursornextCursor fra forrige side
counttrue tar med total i svaret
filterEt filteruttrykk (en delmengde av Google AIP-160) over listens felter, i tillegg til parameterne over

offset finnes ikke – bla med cursor.

Validering​

Parameterne valideres strengt. En ukjent parameter, en verdi som ikke kan leses, en gjentatt parameter som bare tar én verdi, eller et motstridende par gir 400 med errorCode query_parameter_malformed, og errors[] lister hver feil.

Sortering​

sort kan settes til en av sorteringene endepunktet støtter. Disse finner du på endepunktet i API-referansen. Rader med lik verdi sorteres sekundært på id, så rekkefølgen er deterministisk.

Feil​

Responsformat​

Alle feil følger RFC 9457 og har Content-Type: application/problem+json:

{
"type": "https://api.utlegg.app/problems/report_not_pending",
"status": 422,
"instance": "/reports/123/approve",
"errorCode": "report_not_pending",
"traceId": "4bf92f3577b34da6a3ce929d0e0e4736"
}
FeltNår det er med
typeAlltid. En fast URI per feilkode.
statusAlltid. Speiler HTTP-status.
errorCodeAlltid. Stabil nøkkel – bruk denne til å forgrene logikk i klienten. Generiske feil har egne koder, for eksempel unauthorized, not_found, request_validation_failed og internal_error.
errorsNår feilen gjelder bestemte felt eller parametere: én oppføring per feil, med code og pointer (JSON Pointer inn i body), parameter (query-parameter) eller params.
instanceStien i forespørselen.
traceIdForespørselens trace-ID. Oppgi denne til support.

Feilsvarene har ingen menneskelesbar tekst – klienten eier tekstene og velger dem ut fra errorCode.

errorCode for forretningsfeil​

Forretningsfeil gir en stabil errorCode-streng i responsen. Eksempler:

errorCodestatusNår
report_not_pending422Forsøk på å godkjenne/avvise rapport som ikke er PENDING
report_no_expenses400Innsendt rapport mangler utlegg
subscription_feature_not_available402Forsøk på å bruke en feature som ikke er i abonnementet
account_blocked403Brukeren er blokkert i organisasjonen
account_deleted403Kontoen er slettet
flow_validation_failed422Flyt-konfigurasjon er ugyldig
invitation_creator_no_longer_authorized422Den som opprettet invitasjonen har ikke lenger nødvendig tilgang til å tildele rollen
role_not_found404Rollen finnes ikke
system_role_immutable403Forsøk på å endre eller slette en systemrolle via rolle-API-et
role_cross_tenant403Rollen tilhører en annen organisasjon enn den i forespørselen
report_deleted422Forsøk på å endre en slettet rapport

En full oversikt over alle feilkoder med beskrivelse finner du på GET /error-codes.

Anbefalt klientmønster:

if (!res.ok) {
const body = await res.json();
switch (body.errorCode) {
case 'report_not_pending':
// vis bruker-vennlig melding, ikke retry
break;
case 'subscription_feature_limit_reached':
// tilby oppgradering
break;
default:
// generisk fallback, logg traceId
}
}

Hvordan rapportere en feil​

Når du melder inn en feil til support, ta med:

  1. traceId fra responsbody, eller verdien i traceresponse-headeren – den peker rett på forespørselen og er det mest presise vi kan slå opp på.
  2. errorCode, status og instance fra responsbody – eller hele body-en.
  3. Tidspunkt (UTC, gjerne med sekundoppløsning) og organisasjons-ID/handle.
  4. Token-type (PAT, SAT, eller bruker-session) – ikke selve tokenet.
  5. Minimal repro: cURL-kall eller payload som utløser feilen.

Eksempel på et godt feilkall i logg på din side:

2026-05-06T10:14:22Z org=abc traceId=4bf92f3577b34da6a3ce929d0e0e4736 errorCode=flow_validation_failed status=422 path=/flows/123/publish

Med traceId finner vi forespørselen direkte; med tidspunkt + organisasjon + path finner vi den manuelt.

Rate limits​

De fleste endepunktene har ingen egen grense, men noen offentlige eller dyre operasjoner har det:

  • Kvitteringsskanning (/capture/attachments/*) – 5 kall/min per IP-adresse uten innlogging, 20 kall/min per bruker eller token med innlogging.
  • Revisjonsloggen – 120 kall/min per bruker eller token for GET /organizations/{organizationId}/audit-trail, og 10 kall/min for eksport med GET /organizations/{organizationId}/audit-trail/export.

API-et kan i tillegg begrense antall kall per organisasjon per minutt. Da har svarene headerne RateLimit-Policy og RateLimit, som viser grensen og hvor mye som er igjen. Går du over grensen, får du en 429-respons med errorCode tenant_rate_limit_exceeded.

Alle responser som sendes ved rate-limiting eller overbelastning har headeren Retry-After. Vent minst så mange sekunder som den oppgir før du sender et nytt API-kall.

Sporing​

Alle svar har headeren traceresponse. Feilsvar har også trace-ID-en i feltet traceId. Send trace-ID-en til support når du rapporterer en feil.

Sender du headeren traceparent (W3C Trace Context), bruker API-et trace-ID-en din. Da finner du kallet i dine egne logger.

Brukerinnlogging (web og mobil)​

Web og mobil bruker ordinær auth-flyt med refresh-tokens. Støttede OAuth-leverandører inkluderer Apple, Google, Microsoft Entra ID og Vipps. Du trenger normalt ikke å implementere denne flyten selv – bruk PAT eller SAT for egne integrasjoner.

AI-assistenter (MCP)​

En bruker kan også koble en AI-assistent som Claude til API-et via OAuth og MCP (Model Context Protocol) på https://api.utlegg.app/mcp. Tilgangen er skrivebeskyttet og begrenset til brukerens egne roller. Se AI-assistenter og MCP for hvordan tilkobling, samtykke og tilbakekalling fungerer.

Ekstern tilgang for regnskapsfører eller rådgiver​

En organisasjons-Admin kan gi en ekstern praktiker (typisk en regnskapsfører eller controller som allerede har en Utleggsappen-brukerkonto fra en annen organisasjon) midlertidig tilgang til egen organisasjon – uten å opprette et vanlig medlemskap eller sende invitasjon. Dette gjøres i dag kun via API-et; det finnes ikke et eget punkt for dette i dashbordet.

curl -X POST https://api.utlegg.app/organizations/{organizationId}/access-grants \
-H "Authorization: Bearer <admin-PAT>" \
-H "Prefer: contract=next" \
-H "Content-Type: application/json" \
-d '{"userId": "<bruker-uuid>", "roleId": "<rolle-id>", "expiresInDays": 90}'
  • Bruker: mottakeren må ha en eksisterende Utleggsappen-brukerkonto – det sendes ingen invitasjon på e-post.
  • Rolle: du velger selv hvilken organisasjonsrolle (system- eller egendefinert) praktikeren skal ha – fra lesetilgang til full Admin. Å gi ACCOUNT_OWNER-rollen krever at du selv har den rollen i organisasjonen.
  • Varighet: standard 90 dager, kan settes opp til maks 365 dager (expiresInDays). Tilgangen utløper automatisk – det finnes ikke en _EXPIRED-hendelse, kun en stille filtrering ved lesing.
  • Forny: kall samme endepunkt på nytt med samme bruker, organisasjon og rolle – dette forlenger utløpsdatoen fremfor å opprette en ny tilgang.
  • Tilbakekall: DELETE /organizations/{organizationId}/access-grants/:id.
  • Oversikt: GET /organizations/{organizationId}/access-grants viser organisasjonens egne tildelinger; en praktiker kan selv se GET /users/me/access-grants for tilganger på tvers av organisasjoner.

Alt knyttet til denne tilgangstypen lagres i revisjonsloggen (tildelt, fornyet, tilbakekalt) – se Sporbarhet, sikkerhet og kontroll.

Reagere på hendelser​

Bruk SSE for å reagere på hendelser. Åpne én strøm med GET /sse/events. Strømmen sender alle hendelser du har tilgang til. Les mer i Sanntid, dypelenker og notifikasjoner.

Generelle webhook-abonnement utenom flyt er på roadmap – kontakt support hvis du har et konkret behov.

Se også​