- What the integration does
- In plain terms — without the jargon
- A small glossary
- Digdir / Maskinporten: client, JWT grant and scopes
- System user: System Register, request and BankID approval
- Access packages vs. rights
- Tokens: Maskinporten token and Altinn token exchange
- Per service: tax card, VAT, a-melding, annual accounts, business specification, tax return
- Pitfalls worth avoiding
- Frequently asked questions (FAQ)
- What a customer has to do (BankID approval)
What the integration does
Not technical? Skip straight to "In plain terms — without the jargon" further down, and get the whole picture in everyday words.
Macct submits to the public authorities on behalf of the customer, without the customer sharing a password or logging in manually. The following happens automatically:
- Tax card for employers — fetches from Skatteetaten (the Norwegian Tax Administration) how much tax to withhold from employees' pay.
- VAT return — the value-added-tax statement; delivered via an Altinn 3 app hosted by Skatteetaten.
- Business specification + tax return (limited company) — the underlying figures (formerly called RF-1167) and the company's tax return itself.
- Annual accounts — submitted as form RR0002 to the Register of Company Accounts in Brønnøysund via Altinn.
- A-melding (payroll report) — the monthly payroll-and-tax report; delivered as JSON directly to Skatteetaten's reporting API (the old Altinn 2 channel closed on 15 June 2026).
- Shareholder register statement — the record of who owns the shares. The RF-1086 is built in Skatteetaten's official form format and submitted to the new shareholder register API in a three-step flow (main form → one sub-form per shareholder → confirm).
Three building blocks make this possible: Maskinporten (a kind of ID card that lets one computer prove who it is to another — run by the state via Digdir), a system user (the authorisation you give Macct, approved with BankID in Altinn), and Altinn / Skatteetaten (where the submission is actually delivered). The Central Coordinating Register for Legal Entities at the Brønnøysund registers is used to check the organisation number, your role and that the company is in good standing when you register. All three are explained more fully just below.
In plain terms — without the jargon
Most of this page is technical. Here is the same thing in plain English, using a picture you will recognise from everyday life.
Think of the public authorities — Skatteetaten, Brønnøysund — as a set of locked offices where you hand in paperwork. Normally you go there yourself, log in with BankID and submit. Macct does that job for you. But for a computer to be let in and submit on your behalf, three things have to be in place:
- 1. An ID card for machines (Maskinporten). Just as you show your BankID, the Macct machine has to prove who it is. Maskinporten — a state service from Digdir — gives Macct a digital "ID card" that renews itself automatically. No humans log in; it is machine talking to machine.
- 2. An authorisation from you (the system user). The ID card only says "this is Macct". It does not say that Macct may act for your company specifically. So you sign, once, with BankID an authorisation: "Macct may submit VAT, annual accounts and the like for my company." This authorisation is called a system user. It is limited to exactly what it says, it is traceable, and you can withdraw it at any time.
- 3. The delivery window itself (Altinn / Skatteetaten's APIs). With the ID card and the authorisation in hand, Macct goes to the right "window" at the authorities, hands in the document and gets a receipt back.
In short: Maskinporten = who the machine is. System user = what it is allowed to do, and for whom. Altinn = where it submits. The rest of this page is the detail behind each of those three.
What do you notice as a customer? Almost nothing. You approve one link with BankID the very first time. After that Macct keeps the books and prepares the submissions, and you press "send" when you are ready. Nothing goes off automatically — neither to Skatteetaten nor to Brønnøysund — without your approval.
A small glossary
The rest of this page uses these words over and over. Get them down, and everything else reads without stopping.
| Term | Meaning |
|---|---|
| Token | A time-limited digital access pass. The machine presents it with every API call instead of a username and password. |
| Scope | What a token is allowed to do — e.g. "fetch tax cards" or "write to Altinn instances". A token only carries the scopes the client has been granted in advance. |
| System user | The authorisation a company gives a software system in Altinn, approved with BankID. It says who the system may act for. |
| Access package | A role-based "bundle" of permissions in Altinn (e.g. "VAT") that some apps require in addition to specific rights. |
| Instance | One concrete submission in an Altinn 3 app — a "folder" that receives uploaded documents and is driven through process steps to a receipt. |
| Envelope | The XML wrapper around the tax return itself at submission time: who it concerns, which year, and the reference to Skatteetaten's own draft. |
| Party number | Skatteetaten's internal number for a taxable party. It looks like an organisation number but is not one — it is fetched from their API. |
Digdir / Maskinporten: client, JWT grant and scopes
In short: Macct asks the state for a temporary access pass by presenting a signed digital "stamp". The pass only covers the tasks Macct has been approved for in advance — called scopes — for example fetching tax cards or submitting VAT.
Three things to know about Maskinporten:
- One client per environment. Test and production are entirely separate worlds, each with its own client, its own key and its own scope grants.
- Authentication with a signed key. The client proves who it is with a key registered in Digdir's collaboration portal (Samarbeidsportalen) — no passwords anywhere.
- A token per need. The client signs a short JWT ("here I am, and I want these scopes") and exchanges it for an access token that lasts a few minutes.
POST https://maskinporten.no/token
grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&
assertion=<signed JWT: iss=clientId, aud=maskinporten, scope=...>
The scopes we use
| Scope | For what |
|---|---|
skatteetaten:skattekorttilarbeidsgiver | Fetch the electronic tax card |
skatteetaten:mvameldingvalidering | Pre-validation of the VAT return (see pitfall) |
skatteetaten:mvameldinginnsending | Submission of the VAT return (Skatteetaten's scope requirement, in addition to the Altinn app) |
skatteetaten:innrapporteringamelding | Submit the a-melding and fetch the feedback (Skatteetaten's reporting API) |
skatteetaten:innrapporteringaksjonaerregisteroppgave | Submit the shareholder register statement (RF-1086, three-step flow) |
skatteetaten:formueinntekt/skattemelding | Fetch the current tax return/draft — required for the envelope reference when submitting the tax return (see the per-service section) |
altinn:instances.write | Create/write Altinn 3 app instances (VAT, tax return, annual accounts) |
altinn:authentication/systemregister.write | Register/update the system in the System Register |
altinn:authentication/systemuser.request.read / .write | Create and read system user requests |
skatteetaten:skattekorttilarbeidsgiver — a small deviation gives
invalid_scope and no explanation. Maskinporten also rejects the
entire token request if just one scope in the set is not granted, so the
test and production clients should each have their own scope set (the production
client has, for example, the VAT and a-melding submission scopes that the test
client has not yet been granted).
skatteetaten:formueinntekt/skattemelding and
altinn:instances.read in production — cannot be added yourself in
Samarbeidsportalen; they must be granted by the scope owner
(Skatteetaten/Digdir) on request. Until the grant is in place, Maskinporten
answers invalid_scope to the token request. Plan for this early:
the grant itself is quick, but it happens per environment — and it is easy to
believe "both are set" when only one environment actually got it.
System user: System Register, request and BankID approval
In short: This is your actual authorisation, and it is set up in three steps: Macct registers itself as a "system" with Altinn (done only once), then creates a request for your company, and finally you approve it with BankID. Only then can Macct submit on your behalf.
A system user is the customer's authorisation of the software system in Altinn. The flow has three steps:
1. Register the system (once per environment)
The software system is registered in Altinn's System Register with a system ID of
the form <vendor-orgnr>_macct, the client ID(s) from Maskinporten,
and which rights and access packages the system manages.
POST {altinn}/authentication/api/v1/systemregister/vendor
{ "id": "<orgnr>_macct", "vendor": { "ID": "0192:<orgnr>" },
"clientId": ["..."], "rights": [...], "accessPackages": [...],
"allowedRedirectUrls": ["https://macct.no/altinn/callback"] }
2. Create a system user request per customer
POST {altinn}/authentication/api/v1/systemuser/request/vendor
{ "systemId": "<orgnr>_macct",
"partyOrgNo": "<customer's orgnr>",
"externalRef": "selskap-123",
"rights": [ { "resource": [ { "id": "urn:altinn:resource", "value": "app_skd_formueinntekt-skattemelding-v2" } ] }, ... ],
"accessPackages": [ { "urn": "urn:altinn:accesspackage:merverdiavgift" }, ... ],
"redirectUrl": "https://macct.no/altinn/callback" }
→ the response contains a confirmUrl (am.ui.altinn.no/.../systemuser/request?id=...)
3. The customer approves with BankID
The customer opens the confirmUrl and approves in Altinn. After
approval, the actual system user is looked up (the "bysystem" list), and a
systemUserId is stored on the customer. It is not used directly in the
token — the authorisation itself is carried by externalRef + the
customer's organisation number (below).
externalRef must be unique per system
user. If a customer needs a new system user (for example with extended
access) without losing the old one, the new one must be created with a different
externalRef — otherwise Altinn replies that a system user already
exists for the system ID. A tidy convention (selskap-123,
selskap-123-mva) keeps this manageable.
Access packages vs. rights
In short: Altinn requires two kinds of access at the same time — a broad "role bundle" (that Macct may work with accounting and VAT at all) and a specific "key" to each individual service. If either of the two is missing, the submission is rejected. Macct sets up both for you.
Altinn 3 distinguishes between two types of authorisation, and submission often requires both:
- Rights — point to a specific resource/app, e.g.
app_skd_formueinntekt-skattemelding-v2(tax return),app_brg_aarsregnskap-vanlig-202406(annual accounts),ske-innrapportering-amelding(a-melding). - Access packages — role-based "bundles" that Altinn's policy
engine (PDP) requires in order to instantiate certain apps. We use
urn:altinn:accesspackage:regnskap-okonomi-rapportandurn:altinn:accesspackage:merverdiavgift.
AUTH-00063 "accesspackage is not
found in the referenced system". The System Register is environment-split, so
packages added in test must also be added in prod. Rights alone (without an access
package) tend to give a 403 from the PDP when the app is to be instantiated.
Tokens: Maskinporten token and Altinn token exchange
In short: The access pass from Maskinporten is exchanged for a "building-specific" pass at Altinn, and tied to your authorisation so the submission lands on the right company. Test companies and real companies use separate systems — they must never be mixed, or Altinn won't find the authorisation.
To act on behalf of an enterprise other than the client owner, we bind the token to
the system user via authorization_details (the RAR type
urn:altinn:systemuser):
authorization_details = [{
"type": "urn:altinn:systemuser",
"systemuser_org": { "authority": "iso6523-actorid-upis", "ID": "0192:<customer's orgnr>" },
"externalRef": "selskap-123"
}]
The Maskinporten token is then exchanged for an Altinn token to reach the Storage/App APIs:
GET {altinn}/authentication/api/v1/exchange/maskinporten
Authorization: Bearer <maskinporten token with altinn:instances.write>
→ Altinn JWT used against app instances
Which token for which API?
The most common practical error is using the wrong type of token against the wrong API. The rule is simple once you see it:
| API | Correct token |
|---|---|
| Altinn 3 app instances (VAT return, tax return, annual accounts) | Altinn token — the Maskinporten token exchanged at Altinn (the call above) |
| Skatteetaten's direct APIs (tax card, a-melding, shareholder register, fetch tax return) | Raw Maskinporten token, system-user-bound — without the Altinn exchange |
"None of the configured JWK keys match the received JWT token" —
Skatteetaten validates against Maskinporten's keys and does not recognise
Altinn's signature. And vice versa: a raw Maskinporten token does not reach
Altinn's app APIs. A token is never "almost right" — it is the right issuer for
the right recipient.
maskinporten.no
+ platform.altinn.no, test/demo to test.maskinporten.no +
platform.tt02.altinn.no. If the environments are mixed, the system user
does not resolve (404 / MP-303). We choose the environment per company, not
globally.
Per service: API calls and parameters
Tax card for employers
Directly against Skatteetaten's "Tax card for employers" (v3, advance-tax API) with
a system-user-bound Maskinporten token and the scope
skatteetaten:skattekorttilarbeidsgiver. Host:
api.skatteetaten.no (prod) / api-test.sits.no (test).
Parameters: income year, the employer's organisation number and the employee's
national identity number. Response: deduction type (table/percentage), table number
and deduction rate — which are written onto the employee and used in the payroll
run.
VAT return
Delivered via the Altinn 3 app mva-melding-innsending-v1
(instances.write + system user), not the discontinued direct API. Two XML
documents are built: the return itself (mvamelding, namespace
skattemeldingformerverdiavgift) and a submission wrapper
(mvameldinginnsending). Flow:
1) POST .../instances (create instance, instanceOwner = customer's orgnr)
2) PUT/POST data: mvamelding + wrapper (replace the auto-created element)
3) PUT .../process/next (data → confirmation → feedback)
→ receipt: instanceOwnerPartyId/instanceGuid
The return contains, among other things, skattleggingsperiode (a
two-month term + year), fastsattMerverdiavgift,
mvaSpesifikasjonslinje[], meldingskategori=alminnelig and
skattepliktig>organisasjonsnummer. Optional pre-validation is
available at /api/mva/grensesnittstoette/mva-melding/valider.
A-melding (payroll report)
Delivered as JSON directly to Skatteetaten's reporting API — the old Altinn 2
channel (A02) closed on 15 June 2026. Macct builds the official
Leveranse object from the payroll run: income per recipient,
withholding tax and attachment-of-earnings deductions (negative per recipient,
positive totals in betalingsinformasjon) and employer's national
insurance contributions per zone — with the occupational pension premium as its
own basis line (tilskuddOgPremieTilPensjon), as the code lists
require. The token is system-user-bound with the scope
skatteetaten:innrapporteringamelding.
POST /v1/innsending/{periode}/{opplysningspliktig} (Leveranse JSON + idempotencyKey header)
GET /v1/forsendelser/{forsendelseId} (feedback once it is ready)
The feedback is used for reconciliation: Skatteetaten's calculated withholding tax and employer contributions, the KID/account number and due date, plus any discrepancies with severity. As with everything else, the a-melding is never sent automatically — it is validated first, and a human presses "send".
Shareholder register statement (RF-1086)
Delivered to the Tax Administration's shareholder register API in a
three-step flow, in the official form format (main form 890/RF-1086 +
one sub-form 923/RF-1086-U per shareholder, validated against the Tax
Administration's XSDs). The token is system-user-bound with the scope
skatteetaten:innrapporteringaksjonaerregisteroppgave; every
call carries a mandatory idempotencyKey.
1) POST /{year}/1086H → main form id
2) POST /{year}/{mainformid}/1086U (one call per shareholder)
3) POST /{year}/{mainformid}/bekreft?antall_underskjema=N → forsendelseId
The statement follows the same approval flow as the tax return (draft → review → approve → submit, with SHA-256 integrity checks) and is never sent automatically. VPS-registered companies are blocked (VPS reports on their behalf); companies with multiple share classes or events such as mergers/demergers/reverse splits are referred to skatteetaten.no for now.
Annual accounts (RR0002)
Delivered to the Register of Company Accounts via the Altinn app
app_brg_aarsregnskap-vanlig-202406:
- Two documents are uploaded:
Hovedskjema(RR0002H_M — metadata) andUnderskjema(RR0002U_M — profit/loss and balance sheet with detail lines). - The signing requires a person. The system drives the process up to the signing step, but the signing itself cannot be performed by a system user — for legal reasons the Register of Company Accounts requires a person to sign with ID-porten in Altinn (system-user signing is rejected with a 403). The system prepares and locks everything, the person signs, and the system detects the completed process by polling the instance afterwards.
- About the app name: the
-202406suffix is a version date Brønnøysund can roll for new yearly versions — the name is therefore configurable on our side, not hardcoded.
Business specification and tax return (limited company)
The tax return for a limited company is the most involved flow. It has three parts:
- Build and approve. The business specification (the RF-1167
basis) is built and approved first; then the tax return itself is generated
(v2 format, packaged in
skattemeldingOgNaeringsspesifikasjonRequestwith base64-encoded sub-documents). Submission is never automatic — the status flow isDRAFT → READY_FOR_REVIEW → APPROVED → SUBMITTED, with SHA-256 integrity checks between the steps (a Macct control, not a public requirement) and a mandatory preflight check before anything is sent. - Deliver via the Altinn app. The documents are uploaded to an
instance in
app_skd_formueinntekt-skattemelding-v2and the process is driven up to the confirmation step. - The person confirms. The confirmation task (Task_2) must be
performed by a person with ID-porten — see the person requirement
below.
SUBMITTEDis only set once Skatteetaten's feedback actually saysvalidertOK, never merely because the process step was passed.
The envelope must reference Skatteetaten's own draft
This one is easy to miss, and the error only shows up after the person
has confirmed: Skatteetaten already holds a draft tax return for the company, and
the submission envelope must contain a reference to exactly that document
(dokumentreferanseTilGjeldendeDokument) plus Skatteetaten's own
party number for the company. Both are fetched from the
fetch-tax-return API right before submission:
GET https://api.skatteetaten.no/api/skattemelding/v2/{income year}/{orgnr}
Authorization: Bearer <system-user-bound Maskinporten token,
scope skatteetaten:formueinntekt/skattemelding>
Accept: application/xml
→ response: document id (e.g. SKI:755:14847), document type
(skattemeldingUpersonligUtkast) and party number (10 digits — NOT the orgnr)
→ both go into the envelope before upload
Three details that must be right at the same time:
- Without the reference the submission is rejected with
konvoluttIkkeRiktigFormatertin the feedback. The requirement is in Skatteetaten's API documentation but is not enforced by the XSDs — the XML can validate green locally and still be rejected. The same happens if the organisation number is used where the party number should be. - The system-user binding is the representation itself. A token
with the right scope but without a system user in
authorization_detailsis rejected with "the logged-in user does not have the necessary rights in Altinn to represent the taxpayer". - Fetch the reference fresh per submission. The draft at Skatteetaten can be replaced; an old document id then points at the wrong version.
The person requirement in the final step
As with the annual accounts, Skatteetaten requires a trace to a person
behind the submission: if the confirmation step is completed by machine with a
system user, the process appears to deliver — but the feedback comes back
validertMedFeil /
innkommendeForespoerselManglerSporTilUtfoerende. The right design is
therefore that the system prepares and locks the submission and stops at the
confirmation, and the person completes it with ID-porten — in the Altinn portal
or directly inside the accounting system (the end-user flow below).
Personal confirmation from your own system (ID-porten end-user flow)
The person does not have to be sent to the Altinn portal for the confirmation
step: an end-user system can let the person log in with ID-porten inside the
system's own flow and perform the confirmation via the API — the same pattern
Altinn documents for end-user systems, and how the major vendors deliver.
Register an "API client" in Digdir's Samarbeidsportal (grant
authorization_code + PKCE S256; client authentication
client_secret_post or private_key_jwt), request the
scope openid altinn:instances.write, and exchange the person's
access token for a personal Altinn token:
GET {altinn}/authentication/api/v1/exchange/id-porten (prod)
GET {altinn}/authentication/api/v1/exchange/id-porten?test=true (TT02)
Authorization: Bearer <idporten-access-token>
→ PUT {app}/instances/{instance}/process/next body: {"action":"confirm"}
Authorization: Bearer <personal-altinn-token>
Details worth knowing up front:
- The consent page: ID-porten shows an "Accept / Reject"
page for the data-sharing scopes. If the user picks "Reject", the token is
issued with only
openid/profile— and the exchange responds 403 with no body, because it requires at least onealtinn:scope in the token. The consent is remembered after the first "Accept". - The read scope is not self-service in production:
altinn:instances.readcannot be added on your own in Samarbeidsportalen's production environment. Request onlyaltinn:instances.write— the confirmation is a write operation, and the exchange only needs one altinn: scope. ?test=true: the TT02 exchange requires the parameter for tokens fromtest.idporten.no(403 without it); in production it must be omitted.private_key_jwt: if you choose a key instead of a client secret,audin the client_assertion must be the ID-porten issuer (not the token endpoint), and thekidfrom Samarbeidsportalen is required in the JWT header.- Quick sanity test: a token call with a dummy code
separates client configuration from the rest of the flow —
invalid_clientmeans the client authentication is wrong,invalid_grantmeans the client is set up correctly (the code was intentionally invalid).
The confirmation then carries the trace to the person (the requirement above),
the user never touches Skatteetaten's viewer client (see SMEVB-005 among the
pitfalls), and the status rule is unchanged: "submitted" is only set on
validertOK in the feedback.
BigDecimal with two decimals, and foreign currency is converted at
Norges Bank's rate on the transaction date. No submission happens unless it has been
triggered and approved — the system is built never to send anything "on its own".
-202406,
several of the names carry a version or date token — -v2 for the tax
return, -v1 for the VAT app, v3 for the tax-card API — that
Skatteetaten and Brønnøysund can upgrade over time. All of them are configurable in
Macct, so the live integration follows the current version even if the names in this
text fall behind.
Pitfalls worth avoiding
The points below are the ones that typically cost the most time. Macct is built to handle these situations automatically where possible, so in practice they are rarely something you have to think about.
api.skatteetaten.no. The host
idporten.api.skatteetaten.no validates ID-porten keys and replies 401
to a Maskinporten token — the right host is decisive.- No trailing slash in the URL —
…/v2/2025/<orgnr>/gives a 404 with no explanation;…/v2/2025/<orgnr>hits. - Accept must be exactly
application/xml— the API only servesapplication/xml;charset=UTF-8and replies 406 to everything else (includingtext/xml). In particular, check that your HTTP client does not have an interceptor overriding the Accept header globally — a JSON default somewhere else entirely in the code base can be the whole bug. - The right scope, system-user-bound — without the scope it
already stops at Maskinporten (
invalid_scope); with the scope but without a system user, the API replies "does not have the necessary rights … to represent the taxpayer".
dokumentreferanseTilGjeldendeDokument) and use their party
number — not the organisation number. The XSDs have both fields as optional, so
local schema validation stays green regardless; the rejection only arrives in
the feedback after the person has confirmed. The requirement exists only in the
API documentation's prose. Fetch the reference from the fetch-tax-return API
right before every submission (see the per-service section).applicationmetadata — e.g. the
annual accounts' main document is called Hovedskjema (not "Skjema"),
and the VAT app is called mva-melding-innsending-v1.norskIdentifikator must wrap an
<organisasjonsnummer>, not plain text. Missing mandatory fields
(such as skattepliktig>organisasjonsnummer) give internal app errors
in the process step rather than a clear validation error.AUTH-00063 otherwise).AUTH-00004; use a distinct reference for new/extended system
users.app_skd_formueinntekt-skattemelding-v2 the confirmation task
(Task_2) cannot be completed by a system user: the process appears to deliver,
but the feedback comes back validertMedFeil with reason
innkommendeForespoerselManglerSporTilUtfoerende — the Tax
Administration requires a trace to a person behind the submission. Likewise,
Altinn replies 403 when a system user attempts to sign the annual accounts.
Design the flow so the system prepares and stops, and a person confirms/signs
with ID-porten — and never set a "submitted" status without reading the feedback
document (validertOK).skatt.skatteetaten.no/web/skattemelding-visning), which the person
is sent to for the final review-and-submit, can fail with "Det skjedde en teknisk
feil … SMEVB-005" — observed in both the test environment and production (as of
July 2026), and affecting several end-user systems. Systematic testing shows
that the client's only data call
(GET /api/skattemelding-visning/skattemelding-altinn3) responds
HTTP 500 with that code for all valid non-personal end-user-system
content — even a minimal envelope — regardless of process step, while
empty/corrupt instances yield SMEVB-002. The fault is thus server-side at the
Tax Administration and has been reported to them (keep the
korrelasjonsid header from the error response for the support
case). Meanwhile the instance with the uploaded tax return stays safely locked
in Altinn — it is a blocked final click, not lost data. The robust way around
it is the ID-porten end-user flow described above: the person then confirms
inside the accounting system and never touches the viewer client.Frequently asked questions (FAQ)
What is a system user?
A system user is an authorisation a company grants to a software system (such as Macct) in Altinn, so the system can report to the public authorities on the company's behalf. It is approved with BankID, limited to specific services, traceable, and can be withdrawn at any time.
What is Maskinporten?
Maskinporten is a state OAuth2 service from Digdir for machine-to-machine communication. It gives a software system a time-limited "ID card" (access token) that proves which enterprise the system is acting as, without a human logging in.
What is the difference between Maskinporten and ID-porten?
ID-porten is used when a person logs in (for example with BankID) to use a public service. Maskinporten is used when a computer / system authenticates with no person present. Some APIs (such as VAT pre-validation) appear to require ID-porten; the submission itself goes via Maskinporten and Altinn.
What is the difference between a system user and Maskinporten?
Maskinporten proves who the machine is. A system user states what the machine is allowed to do, and for whom — the authorisation from a specific company. Both are needed: the Maskinporten token is bound to the system user in order to report on behalf of the company.
How does Altinn 3 work for accounting systems?
Altinn 3 offers "apps" (for example for the VAT return and annual accounts) that a software system creates instances in via API. The system exchanges the Maskinporten token for an Altinn token, creates an instance for the customer's organisation number, uploads the data and takes the process through to a receipt.
How does an accounting system submit a VAT return?
Via the Altinn 3 app for the VAT return: the system builds the XML message, creates an instance at Altinn with the customer's organisation number as owner, uploads the message and a submission wrapper, and takes the process through to a receipt. Submission never happens without the user's approval.
Why is the tax return rejected with "konvoluttIkkeRiktigFormatert"?
The submission envelope is missing the reference to Skatteetaten's current tax
return (dokumentreferanseTilGjeldendeDokument), or uses the
organisation number where Skatteetaten's party number should be. Both are fetched
from the fetch-tax-return API right before submission. The requirement is in
Skatteetaten's API documentation but is not enforced by the XSDs — the XML can
therefore validate green locally and still be rejected.
How does the tax-card API work?
Macct fetches the electronic tax card directly from Skatteetaten's "Tax card for employers" API with a system-user-bound Maskinporten token. The response (deduction type, table number and deduction rate) is written onto the employee and used in the payroll run.
What a Macct customer has to do
For Macct to be able to submit the VAT return, annual accounts, tax return, etc. on behalf of your company, we need one one-time approval from you:
- You get a link to Altinn (
am.ui.altinn.no) from Macct. - You log in with BankID and approve the system user request — you must have a role on the company (typically the general manager or chair of the board, or a delegated role) in Brønnøysund/Altinn.
- The approval gives Macct a system user with exactly the access packages and rights stated in the request — no more and no less.
You never share passwords, BankID codes or API keys. The authorisation is scoped, traceable, and you can withdraw it at any time in Altinn under Access management → System access. And even with the authorisation in place, Macct never submits anything unless it has been triggered and approved — submission always requires an explicit human "send".
Macct keeps the books and prepares the submissions — you approve once and press "send" when you are ready.
Try free for 30 days See the Altinn status