Publisert - 09.10.2026

Versioning and Diff

How It Works

The Nompd API uses a version-based diff mechanism that allows you to fetch only the data that has changed since your last request. This is useful for keeping a local cache in sync without downloading the full dataset each time.

Opting in to the versioned envelope

By default, treatment-group and reimbursement-group responses return the data directly (an entries array of plain items for list endpoints, or a single plain object for /{id}) — without currentVersion, version, lastChanged, or isDeleted. This default applies whenever since-version is omitted.

To use the version-based diff workflow described below, add versioned=true to your request (e.g. ?versioned=true or ?since-version=5&versioned=true). Requests that include since-version always return the versioned envelope, regardless of the versioned parameter, since a diff response is meaningless without version metadata.

Version Number

Every response includes a currentVersion number. This is a monotonically increasing integer that increments each time the server syncs with upstream data sources (typically once per day).

Workflow

  Client                              Server
    │                                   │
    │  GET /api/v1/treatment-group   │
    │──────────────────────────────────>│
    │                                   │
    │  { currentVersion: 5, entries: [...all items...] }
    │<──────────────────────────────────│
    │                                   │
    │  (store version = 5 locally)      │
    │                                   │
    │  ... time passes, nightly sync happens ...
    │                                   │
    │  GET /api/v1/treatment-group?since-version=5
    │──────────────────────────────────>│
    │                                   │
    │  { currentVersion: 6, entries: [...only changes...] }
    │<──────────────────────────────────│
    │                                   │
    │  (update version = 6 locally)     │

Step by Step

1. Initial fetch

Fetch all data without since-version, opting in to the versioned envelope with versioned=true:

curl -H "X-API-KEY: key" \
  "https://api.example.com/api/v1/treatment-group?versioned=true"

Response:

{
  "currentVersion": 5,
  "entries": [
    { "treatmentGroup": { "id": "aaa", "name": "Group A" }, "isDeleted": false },
    { "treatmentGroup": { "id": "bbb", "name": "Group B" }, "isDeleted": false }
  ]
}

Store currentVersion: 5 in your system.

2. Subsequent fetches

Pass the stored version as since-version:

curl -H "X-API-KEY: key" \
  https://api.example.com/api/v1/treatment-group?since-version=5

Response (only changes):

{
  "currentVersion": 6,
  "entries": [
    { "treatmentGroup": { "id": "aaa", "name": "Group A (updated)" }, "isDeleted": false },
    { "treatmentGroup": { "id": "ccc", "name": "Group C" }, "isDeleted": false },
    { "treatmentGroup": { "id": "bbb", "name": "Group B" }, "isDeleted": true }
  ]
}

Update your stored version to 6.

3. Apply changes locally

For each item in the diff response:

  • isDeleted: false — Upsert (insert or update) the item in your local store.
  • isDeleted: true — Remove the item from your local store.

An isDeleted: true entry can represent either a deletion from the upstream source or a response-only FEST visibility transition: when an active group loses its final FEST-valid product, the default full response no longer contains that group, so the diff emits a synthetic tombstone to remove any previously cached copy. The database row remains active, and a later FEST match can reactivate the group through a subsequent isDeleted: false diff entry.

4. Handle empty diffs

If nothing changed, the response will have an empty entries array:

{
  "currentVersion": 6,
  "entries": []
}

Checking for changes before downloading

If you download the full dataset instead of using since-version, use GET /api/v1&v2/last-updated first. It returns no group data, only whether treatment groups and/or reimbursement groups changed on or after a UTC date.

  1. Poll last-updated?since=<savedDate>. On the first run, omit since.
  2. Download both resource types on the first run, or when hasChanges is true. Before starting the downloads, note the current UTC date of the poll (use the response's Date header rather than your own clock).
  3. Save that date as savedDate only after all downloads succeed. If a download fails, keep the old date and retry.
curl -si -H "X-API-KEY: key" \
  "https://api.example.com/api/v1/last-updated?since=2026-10-06"

Why the date of the poll, and not of lastUpdated:

  • Changes made after your poll happen on that date or later, so the next since=<savedDate> cannot miss them, even if they happen while you download or after midnight.
  • since=<date of lastUpdated> would stay true forever, because the change itself is on or after midnight of its own date.

Limits of a date-only cursor:

  • A change earlier on the same UTC day as your poll is already in your download, but is reported again by the next poll, so expect one redundant download after a change. Once a poll date has no changes, hasChanges is false.
  • The comparison is against UTC midnight, not your local time zone.
  • The check assumes the server's change times do not move backwards. Reload everything and reset your saved date after a restore or when switching environments.
  • This endpoint is independent of currentVersion, which also increases on syncs that change nothing. Do not mix the two cursors.

Client Implementation Example

public class NompdClient
{
    private long _lastVersion = 0;
    private readonly Dictionary<string, TreatmentGroup> _cache = new();

    public async Task SyncAsync()
    {
        var url = _lastVersion == 0
            ? "/api/v1/treatment-group"
            : $"/api/v1/treatment-group?since-version={_lastVersion}";

        var response = await _httpClient.GetFromJsonAsync<VersionedResponse>(url);

        foreach (var item in response.Items)
        {
            if (item.IsDeleted)
                _cache.Remove(item.Data.Id);
            else
                _cache[item.Data.Id] = item.Data;
        }

        _lastVersion = response.CurrentVersion;
    }
}

Edge Cases

Scenario Behavior
since-version=0 Returns all items (equivalent to full fetch, but includes deleted items)
since-version higher than current Returns empty entries list with current version
Multiple syncs between your requests All accumulated changes are included
Client has never fetched before Omit since-version to get all active items
Group loses its final FEST-valid product Returns isDeleted: true so clients remove it
A FEST-hidden group gains a valid product Returns isDeleted: false so clients upsert it again

Recommendations

  • Always store currentVersion from every response, even if the entries list is empty.
  • Use full fetch for initial load (no since-version). This returns only active items, giving you a clean starting point.
  • Use since-version for subsequent calls. This is more efficient and includes deletion information.
  • Sync at most once per day. Data updates nightly, so more frequent polling gives no benefit.

Søk i Utviklerportalen

Søket er fullført!