Skip to content

What differs between Altinn TT02 and production?

By , founder of Apier

Everything that carries identity, authority or data. TT02 is Altinn's shared test environment, and it runs as a separate world: a TT02 Maskinporten client and a production client are different registrations with different issuer and token endpoint values, certificates and keys are enrolled per environment, the data is synthetic, and delegations approved in test do not exist in production. Nothing carries over by itself. The classic cutover failure follows directly: configuration that worked in TT02, pasted into production, produces a 401 because the signed assertion's audience no longer matches the environment answering it. Note also what TT02 is not: it is Altinn's environment, not Apier's sandbox, which is a separate simulated surface needing no Altinn environment at all.

Two parallel lanes. The TT02 lane holds three boxes: test client, test data and synthetic users. The production lane holds three accented boxes: production client, real delegations and real data. A dashed accent line separates the lanes, labelled with the statement that nothing crosses this line by itself.TT02ProductionTest clientTest dataSynthetic usersProduction clientReal delegationsReal dataNothing crosses this line by itself
The two environments as parallel lanes. Every element is enrolled per lane: clients, keys, data and delegations. The divider is the point of the picture, because nothing crosses it without being re-established on the other side.

What is TT02?

Altinn's shared test environment: the place where integrations against Altinn are built and verified before they face production. It has its own URLs, its own synthetic test data and its own test users, and service owners deploy their apps there first, so the surface you integrate against carries the same shape you will meet in production, filled with data no real company owns. That is what makes it safe to fail in.

Shared is the operative word. You test alongside every other integrator, and alongside service owners verifying their own releases, so treat TT02 as a working environment rather than a frozen replica: what it can tell you is whether your mechanics are right, not what production will look like on any given day. One boundary is worth stating plainly once: TT02 is Altinn's environment, and it is not Apier's sandbox. The two solve different problems, and the last section below draws that line properly.

Why do TT02 and production credentials never overlap?

Because the two environments run separate Maskinporten instances, and a client is registered against exactly one of them. The registration happens in Samarbeidsportalen self-service, per environment: a TT02 client and a production client are different registrations with different client ids, even when both represent the same organisation and the same system. The keys follow the same rule. The public half of each signing key is enrolled in the portal for one environment, so a certificate or key that TT02 accepts means nothing to production. How the signed-assertion flow itself works is owned by the authentication guide.

The configuration follows the registration. Each environment publishes its own issuer and its own token endpoint, which is why a live setup carries values like MASKINPORTEN_ISSUER and MASKINPORTEN_TOKEN_ENDPOINT as explicit configuration rather than constants. The documented cutover failure is the one this page exists to prevent: test values pasted into a production deployment produce a 401 with no useful body content, because the signed assertion names an audience the production token endpoint does not recognise. The operator-facing detail, probes and remediation live in the production setup docs, and what happens to the token after issuance is owned by the token exchange guide.

What passes in TT02 but still fails in production?

Anything that depends on data or authority existing on the production side. The test data is synthetic, so its coverage differs from the real registries, and latency and behaviour can differ too: a green run in TT02 proves your mechanics, not the production reality. The sharpest gap is authority. Delegations and approvals are grants inside one trust domain, so the approval a test user gave your system in TT02 simply does not exist in production, and the whole chain, registration, request and the real customer's approval, must be established again, as the setup walkthrough sequences it.

This is why the first production failure after a clean test run is so disorienting: the code did not change, and yet the call is refused. Read those refusals as environment gaps before debugging anything else, and when the refusal is a 403 or a 500 on the system user chain, the symptom-by-symptom causes are owned by the system user troubleshooting guide. The checklist below orders the cutover so each gap is closed deliberately instead of discovered in production.

The cutover from TT02 to production as an ordered checklist. Each step closes one gap that the environment split creates; none of them happens by itself.
StepWhat you doWhy it matters
Register the production clientCreate the production registration in Samarbeidsportalen self-service.The TT02 client does not exist in production; the client id will differ.
Enroll production keysUpload the public half of the production signing key for that client.Keys are enrolled per environment; TT02 enrollment proves nothing here.
Update issuer and endpoint configSwap issuer and token endpoint values to the production ones, together.Mixed values produce the documented 401: the assertion's audience will not match.
Re-run the delegation chainCreate the request and have the real customer org approve it in Altinn.Test approvals do not exist in production; authority must be granted anew.
Verify with a read-only callMake one call that reads and changes nothing, and confirm it answers cleanly.A config mistake surfaces as a clean failure, not inside a binding action.

Where does Apier's sandbox fit?

Outside both lanes. Apier's sandbox is a simulated surface for testing API shapes: zero-auth endpoints that answer with production-shaped responses built from synthetic data, so you can exercise request formats, response parsing and error handling with no key and no Altinn environment of any kind behind the call. It does not talk to TT02, it does not talk to production, and Apier does not operate inside TT02.

The practical division of labour is clean. Use the sandbox to get your integration code right, because that needs no environment setup at all. Use TT02 when you integrate directly against Altinn with credentials of your own, because that is the environment Altinn provides for exactly that work. And treat the cutover checklist above as the bridge between test and production in the direct case, because the environment split guarantees that no part of it happens on its own.

Make the first call

The sandbox call answers who may act for a company from simulated data, with no key and no Altinn environment. The TypeScript sample is the cutover habit this page argues for: a read-only authority lookup that proves the production chain end to end before anything binding is allowed to run.

# Zero-auth sandbox: who may act for a company, from simulated data.
# No key, and no Altinn environment of any kind behind it.
curl -s https://www.apier.no/api/v1/sandbox/public/company/999999999/authority
// The cutover habit: after flipping config to production values, make
// one read-only call before any binding action. It proves the chain
// end to end without changing anything anywhere.
const res = await fetch(
  "https://www.apier.no/api/v1/company/999999999/authority",
  { headers: { Authorization: `Bearer ${process.env.APIER_API_KEY}` } },
);

if (!res.ok) {
  // Every non-2xx answers the same structured envelope. A 401 here
  // means the credential chain itself is wrong: stop and fix config.
  const { error_code, explanation } = await res.json();
  throw new Error(`${error_code}: ${explanation.summary}`);
}

const { data } = await res.json();
// Read-only: who may act for the company, and how the signing picture
// classifies. If this answers cleanly, the chain works; nothing was
// submitted anywhere.
console.log(data.classification);

Frequently asked questions

Can I reuse my TT02 client in production?
No. A Maskinporten client is registered against one environment, so the TT02 client and the production client are different registrations even when they represent the same organisation and the same system. The production client is created separately in Samarbeidsportalen self-service, gets its own client id, and has its own keys enrolled. Nothing about the TT02 registration, its scopes, its keys or its history, carries over into the production one.
Why does my production call return 401 with config that worked in TT02?
Because the two environments have different issuer and token endpoint values, and a signed assertion built from test values names the wrong audience. The documented failure shape is exactly this: test configuration pasted into a production deployment produces a 401 with no useful body content, because the assertion's aud does not match what the production token endpoint expects. The fix is configuration, not code: update the issuer and endpoint values together.
Do delegations made in TT02 exist in production?
No. Test and production are separate trust domains, and a delegation is a grant inside one of them. A customer approval given against synthetic test users proves your flow works mechanically, but the production system user, the production request and the real customer's approval must all be established again on the production side. Plan the cutover so the approval chain is re-run with the real organisation before anything depends on it.
Do I need TT02 at all if I use Apier?
For API-shape testing, no. Apier's sandbox is a separate simulated surface: zero-auth endpoints that answer with production-shaped responses from synthetic data, needing no Altinn environment at all. That covers request and response shapes, error handling and integration code. TT02 remains Altinn's own environment, and it stays relevant when you integrate directly against Altinn with credentials of your own. Apier does not operate inside TT02, and its sandbox is not TT02.
What should I verify first after cutover?
A read-only call. It exercises the whole production chain, the client, the keys, the issuer and endpoint values, without changing anything anywhere, so a configuration mistake surfaces as a clean failure instead of inside a binding action. An authority lookup is a good candidate because a correct answer also confirms you are looking at real registry data. Only after that call answers cleanly should anything that writes or files be allowed to run.