Ga naar hoofdinhoud

General rules

Introduction

An API provides an interface for presentation layers to interact with a data layer, decoupling them from specific underlying systems and technologies. To ensure consistent and predictable interactions, a data layer's API must adhere to several rules.

Documentation

The API is as good as the accompanying documentation. The documentation of the API must be easily discoverable, searchable and publicly accessible. It is often the primary resource for developers of presentation layers during implementation.

API documentation MUST be provided in the form of an OpenAPI definition document which conforms to the OpenAPI Specification, version 3 or later.

See Documentation in the API Design Rules for more information.

Versioning

The API may evolve over time. It MUST be versioned as follows:

  1. The URI base path MUST include a major version number prefixed with v. Example: https://example.org/v1, https://example.org/v2.
  2. The API MUST send the full version number of the API in the API-Version header. Example: API-Version: 1.2.3, API-Version: 2.1.0.

Example

An example request from a presentation layer:

GET /v1/entities/objects/1234 HTTP/2
Host: example.org

This tells the API that the presentation layer is requesting a resource of version 1 (v1) of the API.

An example of the response headers of the API:

HTTP/2 200 OK
API-Version: 1.2.3

The response indicates that the exact version of the API is 1.2.3.

The data layer MUST facilitate the transition between versions. For example, the data layer SHOULD publish a deprecation schedule and a changelog. See Versioning in the API Design Rules for more information.

Status codes

The API MUST use common HTTP status codes in its responses: 2xx for success, 3xx for redirects, 4xx for errors caused by the presentation layer and 5xx for errors caused by the API.

The following table lists common status codes:

StatusDescription
200The request has succeeded.
304The requested resource is not modified.
400The request is invalid.
404The requested resource does not exist.
406The request could not be accepted according to the content negotiation headers.
415The media type in the request is not supported.
429The server has received too many requests.
500A server error has occurred.
503The server is under maintenance.

Media types

The API MUST use media types to enable open and extensible content negotiation.

  1. A presentation layer MAY send the Accept header in its request. Its value MUST conform to the HTTP semantics. For example, the value may contain a specific media type (e.g. application/json), a media type range (e.g. application/json, application/problem+json) or any media type (*/*).
  2. If a presentation layer sends the Accept header with a media type the API does not support, the API MUST respond with a 415 Unsupported Media Type status code.
  3. The API MUST send the media type of its response in the Content-Type header. Its value MUST conform to the HTTP semantics.
  4. The API MUST send the Vary: Accept header to indicate to a presentation layer that it supports content negotiation for media types. This tells a presentation layer that changing the value of the Accept header in a request will yield a different representation of a resource.
  5. The API MUST send its responses as JSON; it is easy to parse and supported natively in most programming languages.
notitie

To do: make JSON-LD the default, not JSON.

Example

An example request from a presentation layer:

GET /v1/entities/objects/1234 HTTP/2
Host: example.org
Accept: application/json

This tells the API that the presentation layer prefers the response to be serialized as JSON.

An example of the response headers of the API:

HTTP/2 200 OK
Content-Type: application/json
Vary: Accept

The response indicates that the body is serialized as JSON and that a new request to the same resource with a different Accept header value will result in a different representation of the resource.

Languages

Heritage information is available in one or more languages, such as Dutch or English. The API MUST allow presentation layers to request information in a preferred language, even if the API only exposes information in one language.

  1. A presentation layer MAY send the Accept-Language header in its request to indicate which language it prefers. Its value MUST conform to the HTTP semantics.
  2. If a presentation layer sends the Accept-Language header with a language tag that the API does not support, the API MUST respond with a 406 Not Acceptable status code.
  3. If a presentation layer does not send the Accept-Language header, the API MUST send its content in its default language, defined by the data layer.
  4. The API MUST send the language tag of the content in the Content-Language header. Its value MUST conform to the HTTP semantics.
  5. The API MUST NOT serve its content in different languages in one response. Instead, a presentation layer MUST issue separate requests for each language, with different Accept-Language header values.
  6. The API MUST send the Vary: Accept-Language header to indicate to a presentation layer that it supports content negotiation for languages. This informs a presentation layer that changing the value of the Accept-Language header in a request will yield a different, language-aware representation of a resource.

Example

An example request from a presentation layer:

GET /v1/entities/objects/1234 HTTP/2
Host: example.org
Accept-Language: nl

This tells the API that the presentation layer prefers the content to be in Dutch.

An example of the response headers of the API:

HTTP/2 200 OK
Content-Language: nl
Vary: Accept-Language

The response indicates that the content is in Dutch and that a new request to the same resource with a different Accept-Language header value will result in a different representation of the resource.

Character encoding

Character encoding defines how characters are converted into bytes by the data layer for transmission to a presentation layer. The data layer MUST encode all API payload responses using UTF-8, except for payloads that are binary by nature, such as images.

Compression

Compression reduces the size of a response body as it is transmitted to a presentation layer, improving performance and reducing bandwidth use. The API SHOULD support compression. This section lists the primary requirements — see HTTP Semantics for more information.

  1. A presentation layer MAY send the Accept-Encoding header in its request to indicate which compression schemes it supports, such as gzip, br, deflate or zstd. Its value MUST conform to the HTTP semantics.
  2. If a presentation layer sends the Accept-Encoding header, the API MAY compress the response body using one of the schemes the presentation layer supports. The API MUST then send the Content-Encoding header to indicate which scheme it used; its value MUST conform to the HTTP semantics.
  3. If a presentation layer does not send the Accept-Encoding header, or requests only schemes the API does not support, the API MUST send the response body uncompressed, without a Content-Encoding header.
  4. The API MUST send the Vary: Accept-Encoding header to indicate to a presentation layer that responses can differ based on the value of the Accept-Encoding request header. This informs a presentation layer that changing the value of the Accept-Encoding header in a request will yield a differently compressed representation of a resource.

Example

An example request from a presentation layer:

GET /v1/entities/objects/1234 HTTP/2
Host: example.org
Accept-Encoding: gzip, br

This tells the API that the presentation layer can handle the compressed response body with either gzip or br.

An example of the response headers of the API:

HTTP/2 200 OK
Content-Type: application/json
Content-Encoding: br
Vary: Accept-Encoding

The response indicates that the body is a JSON representation compressed with Brotli (br). The Vary: Accept-Encoding header indicates that a new request to the same resource with a different Accept-Encoding header value will result in a differently compressed representation of the resource.

Caching

Caching is a mechanism where presentation layers store responses from the API to reuse them for subsequent requests. The API SHOULD support caching via HTTP headers; it enhances performance by reducing server load and latency. This section lists the primary requirements — see HTTP Caching for more information.

  1. The API SHOULD send the Cache-Control header, to make clear to a presentation layer whether information can be cached and, if so, for how long (e.g. 1 hour, 1 day or 1 week). Its value MUST conform to the HTTP Caching standard.
  2. The API SHOULD send the ETag header with a unique fingerprint of a resource. When the resource changes, the API MUST change its fingerprint.
  3. A presentation layer MAY send the If-None-Match header in its request with one or more ETag values returned by the API. If the resource still has one of the provided ETags, the API MUST respond with the 304 Not Modified status code. Otherwise, the API MUST return the modified resource with a new ETag header value.
  4. The API SHOULD send the Last-Modified header with a timestamp of when the resource was last modified. Its value MUST conform to the HTTP semantics.
  5. A presentation layer MAY send the If-Modified-Since header in its request. If the resource has not been modified since that time, the API MUST respond with the 304 Not Modified status code. Otherwise, the API MUST return the modified resource with a new Last-Modified header value.
  6. If a presentation layer sends both the If-None-Match and If-Modified-Since headers in the same request, the API MUST accept If-None-Match and ignore If-Modified-Since.

Example

An example of the response headers of the API:

HTTP/2 200 OK
Cache-Control: max-age=3600
ETag: "xyz"
Last-Modified: Fri, 28 Aug 2026 04:58:08 GMT

The response indicates that this resource can be cached for 1 hour (max-age=3600) without checking the API, has ETag xyz, and was last modified on Friday 28 August 2026.

Rate limiting

Rate limiting is a traffic control mechanism that caps the number of requests a presentation layer can make to the API within a specific time window. It protects the data layer's infrastructure from overload and abuse. This section lists the primary requirements — see Retry-After and RateLimit header fields for HTTP for more information.

  1. The API SHOULD support rate limiting. The data layer chooses a policy that best fits its situation. For example, the data layer may choose a rate limiting algorithm such as Token Bucket, Fixed Window Counter or Sliding Window. The data layer may also choose a method for identifying presentation layers, for example based on IP address or the User-Agent header.
  2. The API SHOULD send the RateLimit-Policy and RateLimit headers to communicate its rate limiting policy and the current limits for a particular presentation layer.
  3. The API SHOULD send a 429 Too Many Requests status code if a presentation layer has sent too many requests within the current time window.
  4. The API SHOULD send the Retry-After header if a presentation layer has sent too many requests within the current time window, to indicate how long the presentation layer ought to wait before making a new request.

Example

An example of the response headers of the API:

HTTP/2 200 OK
RateLimit-Policy: "default";q=100;w=60
RateLimit: "default";r=50;t=30

The RateLimit-Policy indicates that a presentation layer may send up to 100 requests (q=100) per 60 seconds (w=60). The RateLimit shows 50 of those remain (r=50) and that they may be used within the next 30 seconds (t=30).

An example of the response headers of the API when a rate limit has been reached:

HTTP/2 429 Too Many Requests
Retry-After: 120

The response indicates that a presentation layer has made too many requests and that it can try again after 120 seconds.

Cross-Origin Resource Sharing (CORS)

Cross-Origin Resource Sharing (CORS) is a mechanism that allows browser-based presentation layers to interact with the API. The API MUST support CORS by following the relevant requirements of the CORS specification. This section lists the primary requirements.

  1. A browser-based presentation layer MUST send the Origin header to indicate the origin (scheme, hostname, and optionally port) that caused the request to the API.
  2. The API MUST send the Access-Control-Allow-Origin header. The value SHOULD be * to allow access to the API from any origin. If the API limits access (e.g. via the Authorization header), a specific origin MUST be provided instead of *, and the Access-Control-Allow-Credentials: true header MUST be send.
  3. If the API sends a response with an Access-Control-Allow-Origin value with an explicit origin (rather than the * wildcard), the API MUST also send the Vary: Origin header to indicate to a presentation layer that responses can differ based on the value of the Origin request header.
  4. The API MUST send the Access-Control-Allow-Methods header to specify which HTTP methods are permitted for cross-origin requests.
  5. The API MUST send the Access-Control-Allow-Headers header to specify which HTTP headers are permitted for cross-origin requests.
  6. The API MUST support the HTTP OPTIONS method and send the headers above in response to an OPTIONS request (the preflight request pattern).

Example

An example of a preflight request from a presentation layer:

OPTIONS /v1/entities/objects/1234 HTTP/2
Host: example.org
Origin: https://mywebsite.nl
Access-Control-Request-Method: GET
Access-Control-Request-Headers: Accept, Accept-Language, If-None-Match, If-Modified-Since, Origin

An example of the preflight response headers of the API:

HTTP/2 200 OK
Content-Length: 0
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, OPTIONS
Access-Control-Allow-Headers: Accept, Accept-Language, If-None-Match, If-Modified-Since, Origin
Access-Control-Max-Age: 7200

An example of a regular, non-preflight request from a presentation layer:

GET /v1/entities/objects/1234 HTTP/2
Host: example.org
Origin: https://mywebsite.nl

An example of the regular, non-preflight response headers of the API:

HTTP/2 200 OK
Access-Control-Allow-Origin: *

Error handling

When an error occurs, the API MUST handle errors as follows:

  1. The API MUST return an appropriate HTTP status code, such as 404 or 500.
  2. The API MUST return error information according to Problem Details for HTTP APIs. The error information MUST contain at least the following fields:
NameData typeCardinalityDescription
statusnumber1The HTTP status code. Example: 400, 404, 500.
titlestring1A short, human-readable summary of the problem type. For example: Resource not found for every resource that could not be retrieved by the API.
detailstring1A human-readable explanation specific to this occurrence of the problem.
notitie

To be discussed: add support for the type field, for machine-readable processing?

Example

An example of the response headers of the API:

HTTP/2 404 Not Found
Content-Type: application/problem+json
Content-Language: en

Note that the API has responded with the application/problem+json media type, even though the presentation layer may not have listed it in its Accept header. This is allowed by the HTTP Semantics. Also note the Content-Language header, to make clear that the content is in a particular language, per the Accept-Language header of the presentation layer or, if that header was not provided, the default language of the API.

An example of the response body of the API:

{
"status": 404,
"title": "Resource not found",
"detail": "No heritage object found with ID 1234"
}

Note that the title is generic (it applies to every resource) and that the detail is specific (it applies to a particular resource with a particular ID).

Open access

The API SHOULD be open to any presentation layer without technical constraints, such as authentication (e.g. via the Authorization header) or IP address filtering.

Access should only be restricted to designated presentation layers under specific circumstances, such as legal requirements. This specification does not dictate which technical constraints a data layer should implement; that decision rests with the data layer based on its specific needs.

notitie

To do: rephrase or remove this section - it's not yet clear what the requirements are.

Client identification

The data layer should be able to monitor the usage of its API and advise presentation layers in optimizing their implementations. The data layer should therefore be able to identify individual presentation layers.

  1. A presentation layer SHOULD send the User-Agent header in its requests. The header value SHOULD consist of the name of the system of the presentation layer, the version of its system and the URL of the owner of the presentation layer. The value SHOULD look like this: system/version (url), e.g. MyApp/1.7.6 (https://mymuseum.nl). See the HTTP semantics for more information.
  2. The API MAY respond with a 400 Bad Request status code if the User-Agent header in the request is missing or invalid.

Example

An example request from a presentation layer:

GET /v1/entities/objects/1234 HTTP/2
Host: example.org
User-Agent: MyApp/1.7.6 (https://mymuseum.nl)

This tells the API that the request comes from system MyApp, version 1.7.6, operated by a presentation layer with URL https://mymuseum.nl.