Hör av dig

Fortnox API, från någon som byggt mot det sedan 2014

Vad Fortnox API kan, hur inloggningen fungerar, vilka gränser som gäller och vad som brukar strula. För dig som vill bygga själv, eller vill förstå vad du beställer.

Jag byggde min första koppling mot Fortnox API 2014, åt en webbshop som fortfarande skickar sina order dit varje dag. Sen dess har API:et bytt inloggningsmodell, fått tjänstekonton och ändrat en del på vägen. Det här är genomgången jag själv hade velat ha från början. Den är skriven för utvecklare, men går att följa även om du mest vill förstå vad du beställer.

Vad Fortnox API täcker

Fortnox API är ett REST-API som pratar JSON, med adressen https://api.fortnox.se/3/. Det täcker det mesta som går att göra i Fortnox:

  • Order, offerter och fakturor, inklusive betalningar
  • Kunder, leverantörer och leverantörsfakturor
  • Artiklar, priser och lager
  • Projekt, avtal och återkommande fakturering
  • Verifikationer, konton och räkenskapsår
  • Tidrapportering, anställda och lönetransaktioner
  • Filer och bilagor

Allt finns beskrivet i Fortnox API-dokumentation. Dokumentationen är bra, men den säger inte så mycket om vad som händer när saker går fel. Det är resten av den här sidan till för.

Så fungerar inloggningen med OAuth

Fortnox använder OAuth 2 med så kallad authorization code flow. Gången ser ut så här:

  1. Du skapar din integration i Fortnox utvecklarportal och får ett klient-id och en klienthemlighet.
  2. Kunden skickas till https://apps.fortnox.se/oauth-v1/auth med ditt klient-id, en redirect-adress och de scopes du vill ha.
  3. Kunden loggar in i Fortnox och godkänner att din integration får åtkomst.
  4. Fortnox skickar tillbaka kunden till din redirect-adress med en kod.
  5. Du byter koden mot en access token och en refresh token.

Själva bytet är ett vanligt POST-anrop, där klient-id och klienthemlighet skickas som Basic-autentisering:

curl -X POST https://apps.fortnox.se/oauth-v1/token \
  -u "$CLIENT_ID:$CLIENT_SECRET" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=authorization_code&code=$CODE&redirect_uri=$REDIRECT_URI"

Sen använder du access token i varje anrop:

curl https://api.fortnox.se/3/customers \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Accept: application/json"

Tjänstekonton

Godkänner en vanlig användare kopplingen hänger den ihop med just den personen. Slutar personen, eller tas hens behörighet bort, slutar kopplingen fungera. För integrationer mellan system är det sällan vad du vill.

Lösningen är ett tjänstekonto. Du lägger till parametern account_type=service i inloggningen, och då kopplas åtkomsten till en särskild användare i stället för en person. Det kan bara finnas ett tjänstekonto per klient-id och kund, och bara en systemadministratör hos kunden kan godkänna det. Bygger du något nytt i dag är det här nästan alltid rätt val.

Scopes

Scopes styr vad integrationen får komma åt, till exempel customer, order och article. De skickas med i inloggningen, separerade med mellanslag. Be bara om det du behöver, för varje scope ger både läs- och skrivrätt. Kunden behöver också rätt licens i Fortnox för varje scope, och Fortnox lista över scopes visar vilken som hör till vilket.

Räkna också med att kunden får godkänna kopplingen på nytt om du lägger till fler scopes senare, så det lönar sig att tänka igenom listan från början.

Första anropet på tio minuter

Snabbaste vägen till ett riktigt svar från Fortnox API går via en testdatabas, så att du slipper prova mot någons riktiga bokföring. Så här gör du:

  1. Registrera dig som utvecklare hos Fortnox. Då får du tillgång till Fortnox utvecklarportal.
  2. Skapa en integration i utvecklarportalen. Ge den ett namn, kryssa i scopet customer och fyll i en redirect-adress. Spara klient-id och klienthemlighet.
  3. Skapa en testdatabas. Du kan ha upp till 30 samtidigt.
  4. Godkänn integrationen. Öppna adressen nedan i webbläsaren, logga in med testanvändaren och godkänn.
  5. Byt koden mot tokens. Fortnox skickar dig till din redirect-adress med ?code=… i adressfältet. Koden gäller i tio minuter och fungerar bara en gång, så kör bytet från avsnittet ovan direkt.
  6. Hämta kunderna.

Adressen i steg 4 ser ut så här, med dina egna värden:

https://apps.fortnox.se/oauth-v1/auth?client_id=DITT_KLIENT_ID&redirect_uri=https%3A%2F%2Fexempel.se%2Fcallback&scope=customer&state=valfri-text&access_type=offline&response_type=code

Och själva anropet i steg 6:

curl "https://api.fortnox.se/3/customers?limit=10" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Accept: application/json"

Svaret är en lista med kunder och en liten ruta med sidinformation:

{
  "MetaInformation": { "@TotalResources": 3, "@TotalPages": 1, "@CurrentPage": 1 },
  "Customers": [
    { "CustomerNumber": "1", "Name": "Testkund AB", "City": "Älvsbyn" }
  ]
}

En nytom testdatabas kan sakna kunder, så lägg in ett par för hand först om listan kommer tillbaka tom.

Tokens, och varför de ställer till det

En access token gäller i en timme. En refresh token gäller i 45 dagar, och varje gång du använder den för att hämta en ny access token får du också en ny refresh token. Den gamla slutar fungera direkt. Förnyelsen är ett anrop till samma adress som bytet ovan, med grant_type=refresh_token och din senaste refresh token.

Det låter enkelt, men det är här de flesta kopplingar går sönder:

  • Två processer förnyar samtidigt. Den ena får en ny refresh token och den andra sitter kvar med en som inte längre gäller. Nästa gång står kopplingen still. Låt bara ett ställe i koden förnya, och spara den nya token innan du gör något annat.
  • Kopplingen står oanvänd för länge. Går det mer än 45 dagar utan en förnyelse är refresh token ogiltig, och kunden får godkänna kopplingen igen. Säsongsflöden är lömska här.
  • Felet syns inte. En koppling som tappar sin token slutar tyst att skicka data. Logga varje misslyckad förnyelse och se till att någon får veta det.

Slipp refresh tokens med tjänstekonto

Har kunden godkänt ett tjänstekonto kan du hoppa över hela refresh-dansen. Då hämtar du en ny access token med client credentials när du behöver, med klient-id, klienthemlighet och kundens TenantId. Fortnox beskriver det i sitt inlägg om att slippa refresh tokens.

curl -X POST https://apps.fortnox.se/oauth-v1/token \
  -u "$CLIENT_ID:$CLIENT_SECRET" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -H "TenantId: $TENANT_ID" \
  -d "grant_type=client_credentials"

Det är så Profilbutiken kör i dag, på tjänstekonto med client credentials och utan en enda refresh token. Två processer som förnyar samtidigt, eller en token som går ut efter 45 dagar, kan alltså inte längre ställa till det där. Jag har felsökt just de felen många gånger, så jag är glad att slippa dem. Bygger du en ny koppling skulle jag gå på tjänstekonto från början.

TenantId är kundens databasnummer. Du hittar det som tenantId i den access token du redan har, eller som DatabaseNumber i svaret från /3/companyinformation. Spara det när kunden godkänner kopplingen.

Paginering

Alla listor i Fortnox API kommer i sidor, och du styr dem med parametrarna page och limit. Enligt Fortnox guide om parametrar är standard 100 poster per sida och högst 500. Varje svar har en MetaInformation med @TotalPages och @CurrentPage, och det är dem du loopar på:

page=1
while : ; do
  svar=$(curl -s "https://api.fortnox.se/3/articles?limit=500&page=$page" \
    -H "Authorization: Bearer $ACCESS_TOKEN" -H "Accept: application/json")
  # spara artiklarna i $svar här
  total=$(echo "$svar" | jq '.MetaInformation["@TotalPages"]')
  [ "$page" -ge "$total" ] && break
  page=$((page + 1))
  sleep 0.25
done

Med 500 per sida blir ett artikelregister på 5 000 produkter tio anrop, vilket är ingenting. Det som tar tid är när du sen behöver hämta varje post för sig, och då är det anropsgränsen nedan som styr takten.

Vill du bara ha det som ändrats sedan förra körningen lägger du till lastmodified, till exempel lastmodified=2026-10-01 08:00. Kom ihåg att koda mellanslaget i adressen. Spara tiden för varje lyckad körning och använd den nästa gång, så slipper du läsa om hela registret.

Anropsgränser

Enligt Fortnox beskrivning av anropsgränserna får du göra 300 anrop per minut per klient och kund. Gränsen räknas i ett glidande fönster på fem sekunder, så i praktiken är det 25 anrop per fem sekunder som gäller.

Vid vanlig drift märks det sällan, men väl när du läser in stora mängder på en gång, som hela artikelregistret första gången. Bygg in en paus mellan anropen, så att importen fortsätter i stället för att tappa poster.

Webhooks och websocket

Fortnox har inga vanliga webhooks för ändringar i kundens data. I stället finns en websocket som säger till när något ändras, så att du slipper fråga API:et hela tiden. Du öppnar en enda anslutning till wss://ws.fortnox.se/topics-v1 och lägger till alla dina kunder i den, med din klienthemlighet och deras access tokens:

{
  "command": "add-tenants-v1",
  "clientSecret": "DIN_KLIENTHEMLIGHET",
  "accessTokens": ["Bearer KUNDENS_ACCESS_TOKEN"]
}

Sen väljer du vilka ämnen du vill lyssna på, som customers, orders, invoices eller articles. Varje händelse berättar bara vad som hänt och på vilken post, och resten hämtar du med ett vanligt anrop. Tänk på två saker, enligt Fortnox guide om websocketen:

  • Samma händelse kan komma två gånger. Bygg så att det inte gör något om du hanterar en ändring en extra gång.
  • Spara var du var. Varje händelse har ett löpnummer, en offset. Skickar du med den när du ansluter igen spelas missade händelser upp, upp till 14 dagar bakåt.

Webhooks finns faktiskt också, men bara i utvecklarportalen och för händelser kring själva integrationen, till exempel när någon köper den eller när en licens går ut. För att få veta att en faktura ändrats är det websocketen som gäller. Det kan ändå vara klokt att ha en enkel kontroll med lastmodified en gång om dagen som skyddsnät, eftersom en anslutning som tappar kontakten inte alltid märks direkt.

Vad som brukar strula

Det mesta som går fel mot Fortnox API är samma fyra saker, och alla går att bygga bort från början.

Token som gått ut. En access token gäller en timme, så förnya den i god tid i stället för att vänta på att ett anrop ska nekas.

429, för många anrop. Slår du i gränsen får du svaret 429 Too Many Requests. Vänta några sekunder och försök igen med samma anrop. Försöker du direkt i en tät loop slår du bara i taket igen, eftersom fönstret är fem sekunder långt.

PascalCase överallt. Fälten heter CustomerNumber och Name, inte customerNumber. När du skriver något ska datan dessutom ligga i ett omslag med resursens namn, till exempel {"Customer": {...}}, och listor kommer som Customers. Fel kommer tillbaka i ett ErrorInformation-objekt med ett meddelande och en felkod. Logga båda, för koden är det du söker på när du ska förstå vad som hänt.

Att tömma ett fält. Vill du ta bort ett värde skickar du texten API_BLANK i fältet, enligt Fortnox guide om att ta bort värden. Det står i guiden, men det är lätt att missa.

Färdiga bibliotek

Det finns färdiga bibliotek för de flesta språk, byggda av andra utvecklare. API:et är så pass enkelt att ett bibliotek mest sparar dig inloggningen och modellerna. Tokens, fel och anropsgränser får du ändå tänka igenom själv. Så här ser det ut i oktober 2026:

  • .NET: Fortnox.NET.SDK från Softwerk kom i ny version i januari 2026 och har färdiga modeller för det mesta.
  • .NET, alternativ: Fortnox.NET från Zenta uppdaterades senast i april 2026 och har även stöd för websocketen.
  • Python: pyfortnox syns ofta i sökresultaten, men senaste versionen är från 2020 och bygger på den gamla inloggningen. Anropa hellre API:et direkt med requests eller httpx.
  • Ruby: fortnox-api kom i ny version i september 2026 och använder client credentials, så den passar dig som bygger med tjänstekonto.
  • PHP med Laravel: kfoobar/laravel-fortnox och tarre/laravel-fortnox-api uppdateras båda och sköter förnyelsen av tokens åt dig. Utan Laravel är Guzzle och egna anrop oftast enklast.

Kolla alltid när ett bibliotek senast uppdaterades innan du bygger på det. Fortnox har bytt inloggning mer än en gång, och ett bibliotek som inte hängt med slutar fungera från en dag till en annan.

Fortnox och AI (MCP)

MCP, Model Context Protocol, är en öppen standard som låter AI-assistenter som Claude och ChatGPT använda andra system. En MCP-server för Fortnox ligger mellan assistenten och Fortnox API, så att du kan fråga om obetalda fakturor eller be den lägga upp en kund på vanlig svenska. Det finns redan färdiga sådana, och jag skriver om dem på en egen sida som kommer snart.

Under ytan är det samma API som på resten av den här sidan, med samma inloggning och samma scopes. Därför ska du tänka extra på vilka scopes assistenten får. Varje scope ger ju både läs- och skrivrätt, så en assistent som bara ska svara på frågor om fakturor kan också ändra dem om du ger den invoice.

Integrationslicensen

För att din integration ska få prata med kundens Fortnox behöver kunden en integrationslicens. Den beställs i Fortnox och kostar enligt Fortnox prislista 189 kronor i månaden. Licensen gäller för alla integrationer kunden har, så har kunden redan en app kopplad behövs ingen ny. Nämn den för kunden innan bygget sätter igång, för det är den första frågan som kommer när något inte fungerar.

Vill du hellre att någon annan bygger?

Allt det här går att bygga själv, och har du en utvecklare i huset kan det vara rätt väg. Vill du hellre slippa hålla koll på tokens och anropsgränser bygger jag kopplingen åt dig, till fast pris. Hur det ser ut i verkligheten kan du läsa i caset om Profilbutiken, som pratat med Fortnox sedan 2014. Mer om hur jag jobbar, och om vad det kostar, på sidan om Fortnox-integration.

Uppdaterad 7 oktober 2026

Byggt mot Fortnox API sedan 2014

Profilbutiken, en webbshop med över 5 000 produkter, har skickat order, kunder och artiklar till Fortnox sedan 2014. Kopplingen har uppdaterats i takt med API:et och kör sedan 2026 på tjänstekonto med client credentials, helt utan refresh tokens.

  • Sedan 2014
  • Order, kunder, artiklar
  • Inga refresh tokens sedan 2026
Läs hela caset →

Vanliga frågor

Är Fortnox API gratis?

För att en integration ska få prata med ett Fortnox-konto behöver kunden beställa Fortnox integrationslicens. Enligt Fortnox prislista kostar den 189 kr i månaden, och den gäller för alla integrationer kunden har.

Vad är ett tjänstekonto i Fortnox?

En särskild användare som integrationen loggar in som, i stället för en riktig person. Då slutar inte kopplingen att fungera när personen som godkände den byter jobb. Bara en systemadministratör hos kunden kan godkänna ett tjänstekonto.

Hur länge gäller en access token?

En timme. Med vanlig inloggning förnyar du den med en refresh token, som gäller i 45 dagar och byts ut varje gång du använder den. Med tjänstekonto kan du i stället hämta en ny access token med client credentials när du vill, utan refresh token.

Finns det en gräns för antal anrop?

Ja. Enligt Fortnox gäller 300 anrop per minut per klient och kund, räknat i ett glidande fönster på fem sekunder. I praktiken blir det 25 anrop per fem sekunder, och går du över får du svaret 429.

Finns det ett SDK för Fortnox?

Det finns bibliotek byggda av utvecklare och företag för .NET, Ruby och PHP. Kolla när de senast uppdaterades innan du bygger på dem. För Python finns inget jag skulle lita på i dag, så där är det enklast att anropa API:et direkt.

Har Fortnox webhooks?

Inte för ändringar i kundens data. Där använder Fortnox en websocket som säger till när till exempel en kund eller en faktura ändras. Webhooks finns bara för händelser kring själva integrationen, som när den köps eller när en licens går ut.

Vill du slippa bygga själv?

Jag älskar att höra om företags problem, det brukar dyka upp idéer ganska snabbt om hur man kan lösa dem. Förutsättningslöst, så klart.