Design an API contract
Establish repository evidence first
Before proposing a contract, inspect the repository's routes or generated API,
build and framework configuration, published schemas, compatibility checks,
deployment manifests, tests, and contract documentation. Search for every
contract surface: HTTP, generated clients, published libraries, Kafka events,
and files such as OpenAPI or AsyncAPI definitions.
Identify the current framework, versioning mechanism, error shape,
serialization rules, authentication, consumers, and release gates from that
evidence. Do not assume Ktor, Spring, path versioning, a source layout, or that
HTTP is the repository's public contract. If the evidence is missing, ask for
the contract owner and intended consumers before designing the change.
Define the contract and its owners
Describe:
- the consumer-visible operation, request, response, errors, and invariants;
- authentication and authorization expectations;
- idempotency, pagination, ordering, and retry semantics where relevant;
- the source of truth for the contract and how compatibility is verified;
- the producer, known consumers, and migration owner.
Treat error bodies, headers, status codes, validation rules, generated types,
and library signatures as contract surface when consumers can branch on them.
Follow the repository's existing documentation format rather than imposing a
new one.
Classify compatibility
Usually breaking:
- removing or renaming an operation, field, enum value, header, or public type;
- changing a field's meaning or type;
- making optional input required or tightening accepted input;
- changing an error shape or status that consumers may handle;
- changing authentication, audience, authorization, or identity semantics.
Usually additive:
- adding an optional input or response field;
- adding an operation without changing shared behavior;
- adding an error code only when consumers already parse unknown values
defensively.
Repository compatibility tests and published baselines outrank intent. If a
gate rejects a change, handle it as a breaking change or deliberately update
the baseline through the repository's approved process.
Coordinate a breaking change
- Discover service-to-service consumers represented by Nais
accessPolicy.inbound, ingress/external exposure and authentication
separately, and actual consumers from traffic, telemetry, code search, and
published usage. Use all applicable sources; they can differ.
- Notify each owning team directly and agree on a transition window.
- Use the versioning mechanism already established by the repository. For a
new HTTP version, keep both contracts available during migration when
practical. For a published library, follow its semantic-version and release
rules.
- Mark an HTTP version as deprecated before removal. Use
Deprecation and
Sunset headers when they fit the existing API and gateway behavior.
- Remove the old contract only after the agreed window and after observed use
has stopped.
Record resolved contract and migration decisions through /domain-modeling
when they qualify for the repository's ADR process and fall within the
authorized task. Keep an unchosen recommendation as a candidate; do not ask
again for a documentation route already covered by the task.
Apply Nav boundaries
- Keep Nais
accessPolicy.inbound explicit for internal callers and match it
with the callers' outbound policy. It governs service-discovery traffic and
token grants; it does not restrict traffic arriving through an ingress.
Analyze ingress exposure, edge authentication and application authorization
separately. An empty inbound policy denies the covered internal callers; do
not use wildcards without a deliberate security review.
- Validate the token mechanism selected by the repository. For APIs carrying
user context, validate issuer, audience, signature, expiry, and the relevant
identity claims. Check
acr when the operation requires a high login level.
- Derive user identity from the validated token, not from request input.
- Keep national identity numbers, names, tokens, and other personal data out
of URLs, query parameters, logs, and error details.
- Register a discoverable API in Nav's API catalogue when it is intended for
reuse beyond its immediate consumers.
Deliver evidence
Return the changed contract, compatibility classification, consumer list,
migration plan, authorization impact, documentation update, and fresh results
from the repository's contract and test gates. Separate verified consumers
from inferred or unknown consumers.
Boundaries
Ask first
- Any breaking change consumed outside the repository.
- Removing a permitted consumer or changing production access policy.
- Exposing an API outside its current trust boundary.
Never
- Ship an uncoordinated breaking change.
- Invent consumers, versions, routes, packages, or release rules.
- Trust request-provided identity when a validated identity claim exists.
- Put personal data or credentials in URLs, logs, examples, or errors.
1---2name: api-design-33description: Design or change a published API or event contract using consumer and compatibility evidence. Use for new endpoints, versioning, breaking changes or deprecation; use `kotlin-ktor` for framework implementation and `architecture-review` for wider system boundaries.4---56# Design an API contract78## Establish repository evidence first910Before proposing a contract, inspect the repository's routes or generated API,11build and framework configuration, published schemas, compatibility checks,12deployment manifests, tests, and contract documentation. Search for every13contract surface: HTTP, generated clients, published libraries, Kafka events,14and files such as OpenAPI or AsyncAPI definitions.1516Identify the current framework, versioning mechanism, error shape,17serialization rules, authentication, consumers, and release gates from that18evidence. Do not assume Ktor, Spring, path versioning, a source layout, or that19HTTP is the repository's public contract. If the evidence is missing, ask for20the contract owner and intended consumers before designing the change.2122## Define the contract and its owners2324Describe:2526- the consumer-visible operation, request, response, errors, and invariants;27- authentication and authorization expectations;28- idempotency, pagination, ordering, and retry semantics where relevant;29- the source of truth for the contract and how compatibility is verified;30- the producer, known consumers, and migration owner.3132Treat error bodies, headers, status codes, validation rules, generated types,33and library signatures as contract surface when consumers can branch on them.34Follow the repository's existing documentation format rather than imposing a35new one.3637## Classify compatibility3839Usually breaking:4041- removing or renaming an operation, field, enum value, header, or public type;42- changing a field's meaning or type;43- making optional input required or tightening accepted input;44- changing an error shape or status that consumers may handle;45- changing authentication, audience, authorization, or identity semantics.4647Usually additive:4849- adding an optional input or response field;50- adding an operation without changing shared behavior;51- adding an error code only when consumers already parse unknown values52 defensively.5354Repository compatibility tests and published baselines outrank intent. If a55gate rejects a change, handle it as a breaking change or deliberately update56the baseline through the repository's approved process.5758## Coordinate a breaking change59601. Discover service-to-service consumers represented by Nais61 `accessPolicy.inbound`, ingress/external exposure and authentication62 separately, and actual consumers from traffic, telemetry, code search, and63 published usage. Use all applicable sources; they can differ.642. Notify each owning team directly and agree on a transition window.653. Use the versioning mechanism already established by the repository. For a66 new HTTP version, keep both contracts available during migration when67 practical. For a published library, follow its semantic-version and release68 rules.694. Mark an HTTP version as deprecated before removal. Use `Deprecation` and70 `Sunset` headers when they fit the existing API and gateway behavior.715. Remove the old contract only after the agreed window and after observed use72 has stopped.7374Record resolved contract and migration decisions through `/domain-modeling`75when they qualify for the repository's ADR process and fall within the76authorized task. Keep an unchosen recommendation as a candidate; do not ask77again for a documentation route already covered by the task.7879## Apply Nav boundaries8081- Keep Nais `accessPolicy.inbound` explicit for internal callers and match it82 with the callers' outbound policy. It governs service-discovery traffic and83 token grants; it does **not** restrict traffic arriving through an ingress.84 Analyze ingress exposure, edge authentication and application authorization85 separately. An empty inbound policy denies the covered internal callers; do86 not use wildcards without a deliberate security review.87- Validate the token mechanism selected by the repository. For APIs carrying88 user context, validate issuer, audience, signature, expiry, and the relevant89 identity claims. Check `acr` when the operation requires a high login level.90- Derive user identity from the validated token, not from request input.91- Keep national identity numbers, names, tokens, and other personal data out92 of URLs, query parameters, logs, and error details.93- Register a discoverable API in Nav's API catalogue when it is intended for94 reuse beyond its immediate consumers.9596## Deliver evidence9798Return the changed contract, compatibility classification, consumer list,99migration plan, authorization impact, documentation update, and fresh results100from the repository's contract and test gates. Separate verified consumers101from inferred or unknown consumers.102103## Boundaries104105### Ask first106107- Any breaking change consumed outside the repository.108- Removing a permitted consumer or changing production access policy.109- Exposing an API outside its current trust boundary.110111### Never112113- Ship an uncoordinated breaking change.114- Invent consumers, versions, routes, packages, or release rules.115- Trust request-provided identity when a validated identity claim exists.116- Put personal data or credentials in URLs, logs, examples, or errors.