Overview
The Fortnox integration connects Younium to Fortnox, a Swedish accounting system. It supports bidirectional synchronization of accounts, products, payment terms, currencies, exchange rates, cost centers, projects, and financial accounts, as well as automated invoice posting from Younium into Fortnox when invoices are posted.
Authentication
OAuth 2.0 (Standard Authorization)
The integration uses Fortnox's standard OAuth 2.0 authorization workflow. When activated, Younium requests access to the following Fortnox scopes:
- Article
- Customer
- CostCenter
- Currency
- Settings
- Bookkeeping
- Invoice
- Payment
- Order
- Price
- Project
The OAuth flow works as follows:
- Younium builds an authorization URI using the configured Fortnox Client ID and a redirect URI pointing back to the Younium API (
/api/fortnox/callback). - The user is redirected to Fortnox to approve access.
- Fortnox redirects back to Younium with a one-time authorization code.
- Younium exchanges the authorization code for an access token and a refresh token.
- The access token expiration and refresh token expiration are stored. The access token is refreshed automatically before it expires (with a 5-minute buffer). The refresh token is treated as expiring after 31 days.
Activation and Deactivation
Activating the Integration
During activation, Younium performs the following setup steps automatically:
- Creates a custom field on Account named
Fortnox Customer Number(type: Text). - Creates a custom field list on Account named
Fortnox Delivery Methodpopulated with all availableDefaultDeliveryTypeenum values. - Creates a custom field on Product named
Fortnox Product Number(type: Text). - Creates a custom field on Charge named
Fortnox Product Number(type: Text). - Creates a custom field on OrderProductCharge named
Fortnox Product Number(type: Text). - Creates a custom field on Invoice named
Fortnox Invoice Number(type: Text). - Creates a custom field on Country named
Fortnox country(type: Text). - Creates a custom field list on Account named
Fortnox Account VAT Typepopulated with the values:SEVAT,SEREVERSEDVAT,EUREVERSEDVAT,EUVAT,EXPORT.
The integration also subscribes or unsubscribes from the following application events depending on the settings configured:
InvoicePosted→ triggers thefortnox-post-invoiceaction (controlled by the Post Invoices setting).
Deactivating the Integration
Deactivation removes the stored Fortnox settings and unsubscribes from both the InvoicePosted events.
Synchronization Jobs
All synchronization operations are available as scheduled background jobs. Each job checks that the integration is activated (access token is present) before running.
| Job Display Name | Direction | Minimum Repeat Interval |
|---|---|---|
| Import Fortnox accounts | Fortnox → Younium | Not set (no minimum) |
| Export Younium accounts to Fortnox | Younium → Fortnox | 30 minutes |
| Import Fortnox products | Fortnox → Younium | Not set |
| Import Fortnox cost centers | Fortnox → Younium | Not set |
| Import Fortnox projects | Fortnox → Younium | Not set |
| Import Fortnox payment terms | Fortnox → Younium | Not set |
| Import Fortnox chart of accounts | Fortnox → Younium | Not set |
| Import Fortnox currencies | Fortnox → Younium | 30 minutes |
| Import Fortnox exchange rates | Fortnox → Younium | 30 minutes |
All import jobs use incremental synchronization based on a LastModified timestamp stored in the Fortnox settings, querying Fortnox for records modified after LastModified - 1 day. Jobs that do not use LastModified filtering (currencies, exchange rates) always fetch the full list.
Importing Accounts (Fortnox → Younium)
Fetches all Fortnox customers modified since the last account sync date. For each customer, Younium retrieves the full customer record from Fortnox.
Behavior rules:
- Inactive Fortnox customers that do not already exist in Younium are skipped entirely.
- If the setting Synchronize Only New Entities is enabled, existing Younium accounts are not updated.
- If a customer's currency does not exist in Younium, the import for that customer fails with a logged error and processing continues with the next customer.
Account Field Mapping (Fortnox → Younium)
| Fortnox Field | Younium Field |
|---|---|
Name | Account.Name |
WWW | Account.Domain |
VATNumber | Account.TaxRegistrationNumber |
OrganisationNumber | Account.OrganizationNumber |
CustomerNumber | Custom field: Fortnox Customer Number |
TermsOfPayment | Account.DefaultPaymentTermId (matched by payment term Name) |
OurReference | Account.SalesReference |
YourReference | Account.YourReference |
EmailInvoice | Account.InvoiceEmailAddress |
Currency | Account.CurrencyId (matched by currency Code) |
Active (inverted) | Account.Inactive |
VATType | Custom field: Fortnox Account VAT Type (see VAT type mapping below) |
DefaultDeliveryTypes.Invoice | Custom field: Fortnox Delivery Method |
AccountType | Always set to Customer |
Invoice Address Field Mapping (Fortnox → Younium)
| Fortnox Field | Younium Address Field |
|---|---|
Name | Address.Name |
Address1 | Address.Street |
Address2 | Address.Street2 |
City | Address.City |
ZipCode | Address.Zip |
CountryCode (two-alpha ISO code) | Address.CountryId (matched by Country.TwoAlphaCode) |
Country (Fortnox country name string) | Custom field Fortnox country on the matched Country record |
The invoice address is always created or updated. It is set as Account.DefaultInvoiceAddress.
Delivery Address Field Mapping (Fortnox → Younium)
The delivery address is only created or updated if DeliveryAddress1 is not empty in Fortnox.
| Fortnox Field | Younium Address Field |
|---|---|
DeliveryName | Address.Name |
DeliveryAddress1 | Address.Street |
DeliveryAddress2 | Address.Street2 |
DeliveryCity | Address.City |
DeliveryZipCode | Address.Zip |
DeliveryCountryCode (two-alpha ISO code) | Address.CountryId (matched by Country.TwoAlphaCode) |
DeliveryCountry (Fortnox country name string) | Custom field Fortnox country on the matched Country record |
The delivery address, when created/updated, is set as Account.DefaultDeliveryAddress.
VAT Type Mapping
Younium AccountVatTypes | Fortnox CustomerVATType |
|---|---|
SEVAT | SE_VAT |
SEREVERSEDVAT | SE_ReversedVAT |
EUREVERSEDVAT | EU_ReversedVAT |
EUVAT | EU_VAT |
EXPORT | Export |
Exporting Accounts (Younium → Fortnox)
Exports Younium accounts to Fortnox as customers. Only accounts where AccountType is not Prospect and Inactive is false are exported. If LastExportAccountSync is set, only accounts (or accounts with addresses) modified after that date are included.
Requirements: Each account must have a DefaultPaymentTerm and a Currency assigned. If either is missing the account is skipped with a logged error.
Behavior:
- If the account does not yet have a value in the
Fortnox Customer Numbercustom field, it is created as a new Fortnox customer and the returnedCustomerNumberis written back to the custom field. - If the account already has a
Fortnox Customer Number, it is updated in Fortnox. - When updating an existing customer, any field that is null or empty in Younium is sent to Fortnox as
API_BLANK(a special sentinel value that instructs the Fortnox API to clear that field). - When creating a new customer, null/empty fields are sent as-is (not replaced with
API_BLANK).
Account Field Mapping (Younium → Fortnox)
| Younium Field | Fortnox Field |
|---|---|
Account.Name | Customer.Name |
Account.DefaultInvoiceAddress.Street | Customer.Address1 |
Account.DefaultInvoiceAddress.Street2 | Customer.Address2 |
Account.DefaultInvoiceAddress.Zip | Customer.ZipCode |
Account.DefaultInvoiceAddress.City | Customer.City |
Account.DefaultInvoiceAddress.Country.TwoAlphaCode | Customer.CountryCode |
Account.DefaultDeliveryAddress.Street | Customer.DeliveryAddress1 |
Account.DefaultDeliveryAddress.Street2 | Customer.DeliveryAddress2 |
Account.DefaultDeliveryAddress.Zip | Customer.DeliveryZipCode |
Account.DefaultDeliveryAddress.City | Customer.DeliveryCity |
Account.DefaultDeliveryAddress.Country.TwoAlphaCode | Customer.DeliveryCountryCode |
Account.InvoiceEmailAddress | Customer.EmailInvoice |
Account.InvoiceEmailCcAddresses | Customer.EmailInvoiceCC |
Account.DefaultPaymentTerm.Name | Customer.TermsOfPayment |
Account.SalesReference | Customer.OurReference |
Account.YourReference | Customer.YourReference |
Account.TaxRegistrationNumber | Customer.VATNumber |
Account.OrganizationNumber | Customer.OrganisationNumber |
Account.Currency.Code | Customer.Currency |
Account.Inactive (inverted) | Customer.Active |
Custom field Fortnox Account VAT Type | Customer.VATType (see VAT type mapping above) |
Custom field Fortnox Delivery Method | Customer.DefaultDeliveryTypes.Invoice |
Always Company | Customer.Type |
Delivery Method fallback: If the account does not have the Fortnox Delivery Method custom field set, the export falls back to mapping Younium's native InvoiceDeliveryMethod field as follows:
Younium InvoiceDeliveryMethod | Fortnox DefaultDeliveryType |
|---|---|
Email | Email |
Print | Print |
ElectronicInvoice | ElectronicInvoice |
ExternalPrint | PrintService |
Importing Products (Fortnox → Younium)
Fetches all active Fortnox articles modified since the last product sync. Each article is matched to a Younium product by the custom field Fortnox Product Number.
Behavior:
- If no matching product exists, a new product is created with a single default charge plan and a single default charge.
- If a matching product exists, the product, its first charge plan, and the first charge on that charge plan are updated.
- If a product previously synced from Fortnox is no longer present in the active articles list, its
EndOfNewSalesDateis set to today's date. - The
Fortnox Product Numbercustom field is set on both the Product and the Charge. - The
ProductTypeis always set toSimple. EndOfNewSalesDateis always cleared (set to null) when the product is active in Fortnox.
Product Field Mapping (Fortnox → Younium)
| Fortnox Field | Younium Field |
|---|---|
ArticleNumber | Custom field Fortnox Product Number on Product and Charge |
Description | Product.Name, ChargePlan.Name, Charge.Name |
Importing Payment Terms (Fortnox → Younium)
Fetches all Fortnox terms of payment modified since the last payment term sync.
Payment Term Field Mapping (Fortnox → Younium)
| Fortnox Field | Younium Field | Notes |
|---|---|---|
Code | PaymentTerm.Name | Used as the unique match key |
Description | PaymentTerm.Description | |
Code (parsed as integer) | PaymentTerm.Days | Parsed as an integer; defaults to 0 if not parseable |
Always NetDays | PaymentTerm.TermType |
Existing payment terms are updated if the description or days value differs.
Importing Chart of Accounts (Fortnox → Younium)
Fetches all Fortnox accounts modified since the last chart of accounts sync and creates or updates Younium financial accounts.
Financial Account Field Mapping (Fortnox → Younium)
| Fortnox Field | Younium Field | Notes |
|---|---|---|
Number | FinancialAccount.Code | Used as the unique match key; accounts without a number are skipped |
Description | FinancialAccount.Name | Updated if changed |
Importing Currencies (Fortnox → Younium)
Fetches all currencies from Fortnox (no LastModified filter). New currencies not already present in Younium (matched by Code, case-insensitive) are created.
Currency Field Mapping (Fortnox → Younium)
| Fortnox Field | Younium Field |
|---|---|
Code | Currency.Code |
Description | Currency.Description |
Importing Exchange Rates (Fortnox → Younium)
Fetches all currencies from Fortnox and uses the BuyRate and Date fields on each currency to create exchange rate records in Younium. The base currency (configured in Younium) is skipped. Exchange rates are always stored as conversions to SEK.
Behavior:
- If an open (no
EffectiveToDate) exchange rate already exists for the same currency pair and the Fortnox date is more recent, the existing rate is closed (itsEffectiveToDateis set to the day before the Fortnox date) and a new rate is created from the Fortnox date. - If no open rate exists, the system checks for the most recently closed rate and creates a new rate starting from the Fortnox date (or the day after the last closed rate's end date, whichever is later).
- If no rates exist at all for the currency, a new rate is created starting from the Fortnox date.
Exchange Rate Field Mapping (Fortnox → Younium)
| Fortnox Field | Younium Field |
|---|---|
Code | CurrencyExchangeRate.FromCurrency (matched by code) |
Always SEK | CurrencyExchangeRate.ToCurrency |
BuyRate | CurrencyExchangeRate.Rate |
Date | CurrencyExchangeRate.EffectiveFromDate |
Importing Cost Centers (Fortnox → Younium)
Fetches all Fortnox cost centers modified since the last cost center sync. Only active cost centers are imported. Cost centers are stored as items in a custom field list shared between a configured invoice custom field and invoice line custom field. New cost centers are added only if their Code does not already exist in the list (case-insensitive match).
Prerequisite: The settings must have both CostCenterCustomField (for invoices) and InvoiceLineCostCenterCustomField (for invoice lines) configured, and both must point to the same underlying custom field list.
Cost Center Field Mapping (Fortnox → Younium)
| Fortnox Field | Custom Field List Item Field |
|---|---|
Code | Key |
Description | Value |
Importing Projects (Fortnox → Younium)
Fetches all Fortnox projects modified since the last project sync. Projects are stored as items in a custom field list shared between a configured invoice custom field and invoice line custom field. New projects are added only if their ProjectNumber does not already exist in the list (case-insensitive match).
Prerequisite: The settings must have both ProjectCustomField (for invoices) and InvoiceLineProjectCustomField (for invoice lines) configured, and both must point to the same underlying custom field list.
Project Field Mapping (Fortnox → Younium)
| Fortnox Field | Custom Field List Item Field |
|---|---|
ProjectNumber | Key |
Description | Value |
Invoice Posting (Younium → Fortnox)
When an invoice is posted in Younium (the InvoicePosted event fires) and the Post Invoices setting is enabled, the invoice is automatically sent to Fortnox.
Prerequisites:
- The invoice's account must have a value in the
Fortnox Customer Numbercustom field. If this is missing, the posting fails with an error: "Invoice account is not present in Fortnox. Please check if the account is synched from Fortnox into Younium." - The invoice must have 2000 or fewer invoice rows after expansion. If it exceeds this limit, the posting fails.
Invoice Field Mapping (Younium → Fortnox)
| Younium Field | Fortnox Invoice Field |
|---|---|
Custom field Fortnox Customer Number on Account | CustomerNumber |
Invoice.TotalAmount.CurrencyCode | Currency |
Invoice.InvoiceDate | InvoiceDate |
Invoice.DueDate | DueDate |
Invoice.Notes (see remarks logic below) | Remarks |
Invoice.YourReference | YourReference |
Invoice.OurReference | OurReference |
Invoice.YourOrderNumber | YourOrderNumber |
Invoice.InvoiceAddress.Street | Address1 |
Invoice.InvoiceAddress.Street2 | Address2 |
Invoice.InvoiceAddress.City | City |
Invoice.InvoiceAddress.Zip | ZipCode |
Custom field Fortnox country on Invoice.InvoiceAddress.Country | Country |
Invoice.DeliveryAddress.Name | DeliveryName |
Invoice.DeliveryAddress.Street | DeliveryAddress1 |
Invoice.DeliveryAddress.Street2 | DeliveryAddress2 |
Invoice.DeliveryAddress.City | DeliveryCity |
Invoice.DeliveryAddress.Zip | DeliveryZipCode |
Custom field Fortnox country on Invoice.DeliveryAddress.Country | DeliveryCountry |
Order custom field deliverydate (case-insensitive) | DeliveryDate |
Invoice.Id (as string) | ExternalInvoiceReference1 |
After successful creation in Fortnox, the Fortnox DocumentNumber is written back to the Fortnox Invoice Number custom field on the Younium invoice, and also stored in Invoice.ExternalERPId.
Remarks / Notes Logic
The Remarks field in Fortnox is populated from Invoice.Notes. If the Map Renewal Text On Invoice setting is enabled and the invoice has an associated order that is auto-renewed, termed, active, and has an EffectiveEndDate, the following text is appended to the remarks (with a newline separator if notes already exist):
The current subscription term ends on YYYY-MM-DD
The subscription is automatically renewed at the end of the subscription period.
EU Quarterly Report
If the Map EU Quarterly Report setting is enabled, the integration fetches the full Fortnox customer record and sets EUQuarterlyReport = true on the invoice if the customer's VATType is EU_ReversedVAT.
Invoice Line Ordering
Invoice lines are sent to Fortnox in the following fixed order, regardless of any other sorting:
- All recurring and usage charge lines, ordered by
OrderProduct.ProductLineNumberascending, then byOrderProductCharge.ChargeNumberascending. - All one-off charge lines, ordered by
OrderProduct.ProductLineNumberascending, then byOrderProductCharge.ChargeNumberascending.
Invoice Row Field Mapping (Younium → Fortnox)
For each invoice line, Fortnox invoice rows are created as follows:
Standard Invoice Row
| Younium Field | Fortnox InvoiceRow Field |
|---|---|
Custom field Fortnox Product Number on OrderProductCharge | ArticleNumber |
InvoiceLine.ChargeDescription | Description |
| Calculated quantity (see pricing logic) | DeliveredQuantity |
| Calculated unit price (see pricing logic) | Price |
| Calculated discount percent (see pricing logic) | Discount |
Always Percent | DiscountType |
Sum of TaxItems.TaxRate × 100, cast to integer | VAT |
| Resolved project key (see project/cost center below) | Project |
| Resolved cost center key (see project/cost center below) | CostCenter |
Tiered Charge Line Handling
If an invoice line's OrderProductCharge has CreateInvoiceLinesPerTier = true and ChargeModel = Tiered, the line is expanded into separate rows per tier:
- Only tiers where
FromQuantity <= absolute(InvoiceLine.Quantity)are included, ordered byTierascending. - If the summed tiered amount equals
InvoiceLine.Subtotal.Amount, one row per applicable tier is created with:DeliveredQuantity= tier quantityDescription={ChargeDescription}, {tier.Description}Price=tier.Price.Amount × discountPercent- No
DiscountorDiscountTypefields set.
- If the summed tiered amount does not equal
InvoiceLine.Subtotal.Amount, a single fallback row is created with:DeliveredQuantity= 1Price=InvoiceLine.Subtotal.Amount
Automatic Description Row
After each invoice line's main row(s), an additional description-only row is added (with no price, quantity, or article number) except for one-off charges with ChargeModel = Quantity. The description row contains:
- The formatted quantity (formatted as
0.##, removing trailing zeros) if present, followed by a space. - The unit of measure
DisplayNameif present, followed by a space. - If both a service period start and end date exist: appended as
YYYY-MM-DD to YYYY-MM-DD(preceded by,if a quantity was also present).
This row is only added if either a quantity or a service period is present.
Notes Rows
If the invoice line has a Notes value, additional description-only rows are appended after the description row. The notes are split on newline characters (\\n), and each resulting line is further split into chunks of 255 characters (the maximum Fortnox accepts per row description). Each chunk becomes a separate invoice row with only a Description field set.
Project and Cost Center on Invoice Lines
If the Use Project setting is enabled, the integration resolves the project for each invoice line as follows:
- Reads the custom field on the invoice line named by the setting
InvoiceLineProjectCustomField. - Looks up the custom field list item whose
Valuematches the custom field's value, within the list referenced by that field's configuration (LookupReference). - Uses the list item's
Keyas theProjectvalue on the Fortnox invoice row.
If the Use Cost Center setting is enabled, the same process is applied using InvoiceLineCostCenterCustomField, and the resolved Key is used as CostCenter on the invoice row.
Project and Cost Center on the Invoice Header
If the Use Project setting is enabled, the integration also resolves a project for the invoice header using the same lookup logic but against the invoice-level custom field named by the setting ProjectCustomField. The resolved Key is set on fortnoxInvoice.Project.
If the Use Cost Center setting is enabled, the same applies using CostCenterCustomField, setting fortnoxInvoice.CostCenter.
Invoice Accrual (Fortnox Accrual)
If the Use Fortnox Accrual setting is enabled, the integration creates a Fortnox invoice accrual (InvoiceAccrual) after successfully creating the invoice in Fortnox.
Important: If accrual creation fails, the invoice already created in Fortnox is cancelled automatically.
Eligibility
Only invoice lines where the associated OrderProductCharge.RevenueRecognitionRule.RevenueRecognitionMethod equals MonthlyRecognitionOverTime are included in the accrual.
If no eligible lines exist, no accrual is created.
Requirements
- All eligible invoice lines must have the same project dimension value (if Use Project is enabled). If they differ, the posting fails before the invoice is created in Fortnox.
- All eligible invoice lines must have the same cost center dimension value (if Use Cost Center is enabled). If they differ, the posting fails before the invoice is created in Fortnox.
- Each eligible line's
OrderProductChargemust have both aDeferredRevenue.Codeand aRecognizedRevenue.Code. Both codes must be parseable as numeric-only values (no alphabetic characters); Fortnox does not accept alphabetic account codes.
Accrual Calculation
- Accrual amount: Sum of
Subtotal.Amountacross all eligible lines, converted to SEK using the Fortnox invoice'sCurrencyRate(defaulting to 1 if not provided). Rounded to 2 decimal places using MidpointRounding.AwayFromZero. - Start date: First day of the month containing the earliest
ServicePeriodStartDateacross eligible lines. - End date: Last day of the month containing the latest
ServicePeriodEndDateacross eligible lines. - Monthly amount:
accrualAmount ÷ number of monthsbetween start and end date. Rounded to 2 decimal places using MidpointRounding.AwayFromZero. - Period: Always
MONTHLY.
Accrual Field Mapping (Younium → Fortnox)
| Value | Fortnox InvoiceAccrual Field |
|---|---|
DeferredRevenue.Code (as long integer) | AccrualAccount |
RecognizedRevenue.Code (as long integer) | RevenueAccount |
First day of month of min ServicePeriodStartDate | StartDate |
Last day of month of max ServicePeriodEndDate | EndDate |
| Sum of eligible line subtotals × CurrencyRate | Total |
Fortnox DocumentNumber | InvoiceNumber |
Always MONTHLY | Period |
"Periodisering av kundfaktura {DocumentNumber} från Younium" | Description |
Two InvoiceAccrualRow entries are created:
| Row | Account | Debit | Credit | CostCenter | Project |
|---|---|---|---|---|---|
| Accrual row | AccrualAccount | monthlyAmount | 0 | Resolved cost center key | Resolved project key |
| Revenue row | RevenueAccount | 0 | monthlyAmount | Resolved cost center key | Resolved project key |
Custom Fields Created by the Integration
The following custom fields are created automatically when the integration is set up. They should not be renamed or deleted, as they are referenced by name in the integration logic.
| Entity | Custom Field Name | Type | Notes |
|---|---|---|---|
| Account | Fortnox Customer Number | Text | Stores the Fortnox customer number |
| Account | Fortnox Delivery Method | List | Populated with Fortnox delivery type values |
| Account | Fortnox Account VAT Type | List | Populated with: SEVAT, SEREVERSEDVAT, EUREVERSEDVAT, EUVAT, EXPORT |
| Product | Fortnox Product Number | Text | Stores the Fortnox article number |
| Charge | Fortnox Product Number | Text | Stores the Fortnox article number |
| OrderProductCharge | Fortnox Product Number | Text | Used when creating invoice rows |
| Invoice | Fortnox Invoice Number | Text | Written back after successful posting |
| Country | Fortnox country | Text | Stores the Fortnox country name string (used on invoice addresses, as Fortnox does not accept country codes on invoices) |
Related to