diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml
index f6925ba64aa8..1f1f13bd30bb 100644
--- a/.github/workflows/push.yml
+++ b/.github/workflows/push.yml
@@ -290,7 +290,7 @@ jobs:
       - name: Prepare docker build targets
         id: build_map
         run: |
-          CHUNKS=$(./scripts/ci/generate-build-chunks.sh docker-express docker-next docker-static docker-cypress)
+          CHUNKS=$(./scripts/ci/generate-build-chunks.sh docker-express docker-next docker-static docker-cypress docker-jest)
           echo "CHUNKS: '$CHUNKS'"
           if [[ $CHUNKS != "[]" ]]; then
             echo "::set-output name=BUILD_CHUNKS::$CHUNKS"
@@ -302,7 +302,7 @@ jobs:
         env:
           BASE: 'origin/main'
         run: |
-          CHUNKS=$(./scripts/ci/generate-build-chunks.sh docker-express docker-next docker-static docker-cypress)
+          CHUNKS=$(./scripts/ci/generate-build-chunks.sh docker-express docker-next docker-static docker-cypress docker-jest)
           echo "CHUNKS: '$CHUNKS'"
           if [[ $CHUNKS != "[]" ]]; then
             echo "::set-output name=IMAGES::$(echo $CHUNKS | jq '.[] | fromjson | .projects' -r | tr '\n' ',')"
@@ -311,7 +311,7 @@ jobs:
       - name: Gather unaffected docker images
         id: unaffected
         run: |
-          UNAFFECTED=$(./scripts/ci/list-unaffected.sh docker-next docker-express docker-static docker-cypress)
+          UNAFFECTED=$(./scripts/ci/list-unaffected.sh docker-next docker-express docker-static docker-cypress docker-jest)
           echo "::set-output name=UNAFFECTED::$UNAFFECTED"
 
   tests:
diff --git a/apps/external-contracts-tests/.eslintrc b/apps/external-contracts-tests/.eslintrc
new file mode 100644
index 000000000000..ce8022324655
--- /dev/null
+++ b/apps/external-contracts-tests/.eslintrc
@@ -0,0 +1 @@
+{"extends":"../../.eslintrc","rules":{},"ignorePatterns":["!**/*"]}
\ No newline at end of file
diff --git a/apps/external-contracts-tests/esbuild.json b/apps/external-contracts-tests/esbuild.json
new file mode 100644
index 000000000000..8e334842c701
--- /dev/null
+++ b/apps/external-contracts-tests/esbuild.json
@@ -0,0 +1,34 @@
+{
+  "platform": "node",
+  "external": [
+    "fsevents",
+    "color-string",
+    "color-convert",
+    "@nestjs/microservices",
+    "class-transformer",
+    "cache-manager",
+    "@nestjs/websockets/socket-module",
+    "class-validator",
+    "class-transformer",
+    "@nestjs/microservices/microservices-module",
+    "apollo-server-fastify",
+    "@elastic/elasticsearch",
+    "fastify-swagger",
+    "@nestjs/mongoose",
+    "@nestjs/typeorm",
+    "dd-trace",
+    "express",
+    "http-errors",
+    "graphql",
+    "winston",
+    "pg",
+    "source-map-resolve",
+    "atob",
+    "logform",
+    "pg-native",
+    "form-data",
+    "bull",
+    "pseudomap"
+  ],
+  "keepNames": true
+}
diff --git a/apps/external-contracts-tests/infra/external-contracts-tests.ts b/apps/external-contracts-tests/infra/external-contracts-tests.ts
new file mode 100644
index 000000000000..2d252b3e3b60
--- /dev/null
+++ b/apps/external-contracts-tests/infra/external-contracts-tests.ts
@@ -0,0 +1,31 @@
+import { service, ServiceBuilder } from '../../../infra/src/dsl/dsl'
+import { Base, NationalRegistry } from '../../../infra/src/dsl/xroad'
+import { settings } from '../../../infra/src/dsl/settings'
+
+export const serviceSetup = (): ServiceBuilder<'external-contracts-tests'> => {
+  return service('external-contracts-tests')
+    .namespace('external-contracts-tests')
+    .extraAttributes({
+      dev: { schedule: '0 11 * * *' },
+      staging: { schedule: '0 11 * * *' },
+      prod: { schedule: '0 11 * * *' },
+    })
+    .env({})
+    .secrets({
+      SOFFIA_SOAP_URL: '/k8s/api/SOFFIA_SOAP_URL',
+      SOFFIA_HOST_URL: '/k8s/api/SOFFIA_HOST_URL',
+      SOFFIA_USER: settings.SOFFIA_USER,
+      SOFFIA_PASS: settings.SOFFIA_PASS,
+    })
+    .resources({
+      limits: {
+        cpu: '1',
+        memory: '1024Mi',
+      },
+      requests: {
+        cpu: '500m',
+        memory: '512Mi',
+      },
+    })
+    .xroad(Base, NationalRegistry)
+}
diff --git a/apps/external-contracts-tests/jest-to-dd.ts b/apps/external-contracts-tests/jest-to-dd.ts
new file mode 100644
index 000000000000..e910e6d8c39d
--- /dev/null
+++ b/apps/external-contracts-tests/jest-to-dd.ts
@@ -0,0 +1,33 @@
+import { StatsD } from 'hot-shots'
+import { readFileSync } from 'fs'
+import { resolve } from 'path'
+
+// this is not in use yet, but will be part of the next phase in this development
+
+const client = new StatsD({ mock: true })
+const jestReport = JSON.parse(
+  readFileSync(resolve(process.argv[2]), { encoding: 'utf-8' }),
+) as {
+  testResults: {
+    assertionResults: { fullName: string; status: 'passed' | 'failed' }[]
+  }[]
+}
+const testCasesInfo = jestReport.testResults.flatMap(
+  (testResult) =>
+    testResult.assertionResults.map((test) => ({
+      name: test.fullName as string,
+      status: test.status === 'passed' ? 'success' : 'failure',
+    })) as { name: string; status: 'success' | 'failure' }[],
+)
+const successfulTests = testCasesInfo
+  .filter((tc) => tc.status === 'success')
+  .map((tc) => tc.name)
+const failedTests = testCasesInfo
+  .filter((tc) => tc.status === 'failure')
+  .map((tc) => tc.name)
+
+console.log(`Failed test: ${failedTests}`)
+console.log(`Successful tests: ${successfulTests}`)
+
+successfulTests.forEach((tc) => client.check(tc, client.CHECKS.OK))
+failedTests.forEach((tc) => client.check(tc, client.CHECKS.CRITICAL))
diff --git a/apps/external-contracts-tests/jest.config.js b/apps/external-contracts-tests/jest.config.js
new file mode 100644
index 000000000000..c1d7b7132bd4
--- /dev/null
+++ b/apps/external-contracts-tests/jest.config.js
@@ -0,0 +1,15 @@
+module.exports = {
+  preset: '../../jest.preset.js',
+  transform: {
+    '^(?!.*\\.(js|jsx|ts|tsx|css|json)$)': '@nrwl/react/plugins/jest',
+    '^.+\\.[tj]sx?$': 'ts-jest',
+  },
+  globals: {
+    'ts-jest': {
+      tsConfig: '<rootDir>/tsconfig.json',
+    },
+  },
+  moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html'],
+  displayName: 'external-contracts-tests',
+  modulePathIgnorePatterns: ['<rootDir>/main.spec.ts'],
+}
diff --git a/apps/external-contracts-tests/main.spec.ts b/apps/external-contracts-tests/main.spec.ts
new file mode 100644
index 000000000000..5afa4e997bf4
--- /dev/null
+++ b/apps/external-contracts-tests/main.spec.ts
@@ -0,0 +1,3 @@
+import * as testSuites from './test-suites/'
+
+console.log('Forcing esbuild visit to testSuites:', testSuites)
diff --git a/apps/external-contracts-tests/test-suites/index.ts b/apps/external-contracts-tests/test-suites/index.ts
new file mode 100644
index 000000000000..1dad1b5e4cc3
--- /dev/null
+++ b/apps/external-contracts-tests/test-suites/index.ts
@@ -0,0 +1 @@
+export * from './soffia.spec'
diff --git a/apps/external-contracts-tests/test-suites/soffia.spec.ts b/apps/external-contracts-tests/test-suites/soffia.spec.ts
new file mode 100644
index 000000000000..18d27af719a0
--- /dev/null
+++ b/apps/external-contracts-tests/test-suites/soffia.spec.ts
@@ -0,0 +1,25 @@
+// NOTE: To run this locally, you'll need to portforward soffia and set
+// the environment variable "SOFFIA_SOAP_URL" to https://localhost:8443
+// kubectl port-forward svc/socat-soffia 8443:443 -n socat
+import { NationalRegistryApi } from '@island.is/clients/national-registry-v1'
+
+describe('is.island.external.national', () => {
+  let client: NationalRegistryApi
+  beforeAll(async () => {
+    client = await NationalRegistryApi.instantiateClass({
+      baseSoapUrl: process.env.SOFFIA_SOAP_URL!,
+      user: process.env.SOFFIA_USER!,
+      password: process.env.SOFFIA_PASS!,
+      host: process.env.SOFFIA_HOST_URL!,
+    })
+  })
+  it('should get user correctly', async () => {
+    const user = await client.getUser('0101302989')
+    expect(user.Fulltnafn).toEqual('Gervimaður Ameríka')
+  })
+  it('throws error if user is not found', async () => {
+    await expect(client.getUser('0123456789')).rejects.toThrow(
+      'user with nationalId 0123456789 not found in national Registry',
+    )
+  })
+})
diff --git a/apps/external-contracts-tests/tsconfig.json b/apps/external-contracts-tests/tsconfig.json
new file mode 100644
index 000000000000..a549d92b875b
--- /dev/null
+++ b/apps/external-contracts-tests/tsconfig.json
@@ -0,0 +1,8 @@
+{
+  "extends": "../../tsconfig.base.json",
+  "compilerOptions": {
+    "outDir": "../../dist/out-tsc",
+    "module": "commonjs",
+    "types": ["jest", "node"]
+  }
+}
diff --git a/charts/islandis/values.dev.yaml b/charts/islandis/values.dev.yaml
index af4659c1f6d7..dbe829be354a 100644
--- a/charts/islandis/values.dev.yaml
+++ b/charts/islandis/values.dev.yaml
@@ -630,6 +630,54 @@ endorsement-system-api:
       eks.amazonaws.com/role-arn: 'arn:aws:iam::013313053092:role/endorsement-system-api'
     create: true
     name: 'endorsement-system-api'
+external-contracts-tests:
+  enabled: true
+  env:
+    NODE_OPTIONS: '--max-old-space-size=976'
+    SERVERSIDE_FEATURES_ON: ''
+    XROAD_BASE_PATH: 'http://securityserver.dev01.devland.is'
+    XROAD_BASE_PATH_WITH_ENV: 'http://securityserver.dev01.devland.is/r1/IS-DEV'
+    XROAD_NATIONAL_REGISTRY_REDIS_NODES: '["clustercfg.general-redis-cluster-group.5fzau3.euw1.cache.amazonaws.com:6379"]'
+    XROAD_NATIONAL_REGISTRY_SERVICE_PATH: 'IS-DEV/GOV/10001/SKRA-Protected/Einstaklingar-v1'
+    XROAD_TJODSKRA_API_PATH: '/SKRA-Protected/Einstaklingar-v1'
+    XROAD_TJODSKRA_MEMBER_CODE: '10001'
+    XROAD_TLS_BASE_PATH: 'https://securityserver.dev01.devland.is'
+    XROAD_TLS_BASE_PATH_WITH_ENV: 'https://securityserver.dev01.devland.is/r1/IS-DEV'
+  grantNamespaces: []
+  grantNamespacesEnabled: false
+  healthCheck:
+    liveness:
+      initialDelaySeconds: 3
+      path: '/'
+      timeoutSeconds: 3
+    readiness:
+      initialDelaySeconds: 3
+      path: '/'
+      timeoutSeconds: 3
+  image:
+    repository: '821090935708.dkr.ecr.eu-west-1.amazonaws.com/external-contracts-tests'
+  namespace: 'external-contracts-tests'
+  replicaCount:
+    default: 2
+    max: 3
+    min: 2
+  resources:
+    limits:
+      cpu: '1'
+      memory: '1024Mi'
+    requests:
+      cpu: '500m'
+      memory: '512Mi'
+  schedule: '0 11 * * *'
+  secrets:
+    CONFIGCAT_SDK_KEY: '/k8s/configcat/CONFIGCAT_SDK_KEY'
+    SOFFIA_HOST_URL: '/k8s/api/SOFFIA_HOST_URL'
+    SOFFIA_PASS: '/k8s/service-portal/SOFFIA_PASS'
+    SOFFIA_SOAP_URL: '/k8s/api/SOFFIA_SOAP_URL'
+    SOFFIA_USER: '/k8s/service-portal/SOFFIA_USER'
+  securityContext:
+    allowPrivilegeEscalation: false
+    privileged: false
 github-actions-cache:
   args:
     - '--tls-min-v1.0'
@@ -807,6 +855,7 @@ namespaces:
     - 'air-discount-scheme'
     - 'github-actions-cache'
     - 'user-notification'
+    - 'external-contracts-tests'
 search-indexer-service:
   enabled: true
   env:
diff --git a/infra/src/uber-charts/islandis.ts b/infra/src/uber-charts/islandis.ts
index b3cf5981c0f6..39cef5a0736c 100644
--- a/infra/src/uber-charts/islandis.ts
+++ b/infra/src/uber-charts/islandis.ts
@@ -32,6 +32,8 @@ import { serviceSetup as adsApiSetup } from '../../../apps/air-discount-scheme/a
 import { serviceSetup as adsWebSetup } from '../../../apps/air-discount-scheme/web/infra/web'
 import { serviceSetup as adsBackendSetup } from '../../../apps/air-discount-scheme/backend/infra/backend'
 
+import { serviceSetup as externalContractsTestsSetup } from '../../../apps/external-contracts-tests/infra/external-contracts-tests'
+
 import { EnvironmentServices } from '.././dsl/types/charts'
 
 const endorsement = endorsementServiceSetup({})
@@ -74,6 +76,8 @@ const adsApi = adsApiSetup({ adsBackend })
 const adsWeb = adsWebSetup({ adsApi })
 const githubActionsCache = githubActionsCacheSetup()
 
+const externalContractsTests = externalContractsTestsSetup()
+
 export const Services: EnvironmentServices = {
   prod: [
     appSystemApi,
@@ -142,6 +146,7 @@ export const Services: EnvironmentServices = {
     githubActionsCache,
     userNotificationService,
     userNotificationWorkerService,
+    externalContractsTests,
   ],
 }
 
diff --git a/nx.json b/nx.json
index 44ad46d96d46..1b626d29aad5 100644
--- a/nx.json
+++ b/nx.json
@@ -386,6 +386,9 @@
     "email-service": {
       "tags": []
     },
+    "external-contracts-tests": {
+      "tags": []
+    },
     "feature-flags": {
       "tags": []
     },
diff --git a/package.json b/package.json
index 4c81f4c22db6..4617e77ec675 100644
--- a/package.json
+++ b/package.json
@@ -161,6 +161,7 @@
     "graphql-type-json": "0.3.2",
     "handlebars": "4.7.7",
     "http-cache-semantics": "4.1.0",
+    "hot-shots": "9.0.0",
     "http-proxy-middleware": "0.19.1",
     "hypher": "0.2.5",
     "identicon.js": "2.3.3",
diff --git a/scripts/ci/90_docker-jest.sh b/scripts/ci/90_docker-jest.sh
new file mode 100755
index 000000000000..90ffe36b9bfa
--- /dev/null
+++ b/scripts/ci/90_docker-jest.sh
@@ -0,0 +1,10 @@
+#!/bin/bash
+set -euxo pipefail
+
+DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
+
+# shellcheck disable=SC1091
+source "$DIR"/_common.sh
+
+# Building Docker images for jest tests
+exec "$DIR"/_docker.sh Dockerfile output-jest
diff --git a/scripts/ci/Dockerfile b/scripts/ci/Dockerfile
index c5a945d57fa9..7d00522e5fc9 100644
--- a/scripts/ci/Dockerfile
+++ b/scripts/ci/Dockerfile
@@ -39,26 +39,26 @@ ENV NODE_ENV=production
 
 WORKDIR /webapp
 
+# Adding user for running the app
+RUN addgroup runners && adduser -D runner -G runners
+
+FROM output-base as output-base-with-pg
+
 RUN npm install -g \
     sequelize \
     sequelize-cli \
     pg
-    # npx
-    # logform \
-    # dd-trace
 
-# Adding user for running the app
-RUN addgroup runners && adduser -D runner -G runners
 USER runner
 
-FROM output-base as output-express
+FROM output-base-with-pg as output-express
 
 COPY --from=builder /build/${APP_DIST_HOME} /webapp/
 
 ENTRYPOINT []
 CMD [ "node", "main.js" ]
 
-FROM output-base as output-next
+FROM output-base-with-pg as output-next
 
 ENV PORT=4200
 
@@ -91,3 +91,15 @@ RUN apk update && \
 ADD scripts/dockerfile-assets/nginx/* /etc/nginx/templates
 ADD scripts/dockerfile-assets/bash/extract-environment.sh /docker-entrypoint.d
 COPY --from=builder /build/${APP_DIST_HOME} /usr/share/nginx/html
+
+FROM output-base as output-jest
+
+RUN echo 'module.exports = {};' > jest.config.js
+
+RUN npm install -g jest
+
+COPY --from=builder /build/${APP_DIST_HOME} /webapp/
+
+USER runner
+
+CMD [ "jest", "main.spec.js" ]
\ No newline at end of file
diff --git a/workspace.json b/workspace.json
index 54502103e5ad..7c64bd088762 100644
--- a/workspace.json
+++ b/workspace.json
@@ -3993,6 +3993,51 @@
         }
       }
     },
+    "external-contracts-tests": {
+      "root": "apps/external-contracts-tests",
+      "sourceRoot": "apps/external-contracts-tests/src",
+      "projectType": "application",
+      "prefix": "external-contracts-tests",
+      "schematics": {},
+      "architect": {
+        "lint": {
+          "builder": "@nrwl/linter:lint",
+          "options": {
+            "linter": "eslint",
+            "tsConfig": ["apps/external-contracts-tests/tsconfig.json"],
+            "exclude": [
+              "**/node_modules/**",
+              "!apps/external-contracts-tests/**/*"
+            ]
+          }
+        },
+        "build": {
+          "builder": "@irdnis/esbuildnx:build",
+          "outputs": ["{options.outputPath}"],
+          "options": {
+            "outputPath": "dist/apps/external-contracts-tests",
+            "main": "apps/external-contracts-tests/main.spec.ts",
+            "tsConfig": "apps/external-contracts-tests/tsconfig.json"
+          },
+          "configurations": {
+            "production": {
+              "optimization": true,
+              "extractLicenses": true,
+              "inspect": false
+            }
+          }
+        },
+        "external-test": {
+          "builder": "@nrwl/jest:jest",
+          "options": {
+            "jestConfig": "apps/external-contracts-tests/jest.config.js",
+            "passWithNoTests": true
+          },
+          "outputs": ["coverage/apps/external-contracts-tests"]
+        },
+        "docker-jest": {}
+      }
+    },
     "feature-flags": {
       "root": "libs/feature-flags",
       "sourceRoot": "libs/feature-flags/src",
diff --git a/yarn.lock b/yarn.lock
index 6fb893b0608a..b24cb1afdb1b 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -10746,7 +10746,7 @@ binary-extensions@^2.0.0:
   resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d"
   integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==
 
-bindings@^1.5.0:
+bindings@^1.3.0, bindings@^1.5.0:
   version "1.5.0"
   resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df"
   integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==
@@ -17171,6 +17171,13 @@ hosted-git-info@3.0.8, hosted-git-info@^2.1.4, hosted-git-info@^3.0.6, hosted-gi
   dependencies:
     lru-cache "^6.0.0"
 
+hot-shots@9.0.0:
+  version "9.0.0"
+  resolved "https://registry.yarnpkg.com/hot-shots/-/hot-shots-9.0.0.tgz#b88421aa81c1ef37f4cc53ade7f1e3daaa584b5e"
+  integrity sha512-fpljto22PvfzDGznnzUpWgFMgccyZRtWo+fY8R4ktwipkv3ywDyeaTLijYaM629DEZvtnEDAN00yV6zxzivnpQ==
+  optionalDependencies:
+    unix-dgram "2.0.x"
+
 hpack.js@^2.1.6:
   version "2.1.6"
   resolved "https://registry.yarnpkg.com/hpack.js/-/hpack.js-2.1.6.tgz#87774c0949e513f42e84575b3c45681fade2a0b2"
@@ -29055,6 +29062,14 @@ universalify@^2.0.0:
   resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717"
   integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==
 
+unix-dgram@2.0.x:
+  version "2.0.4"
+  resolved "https://registry.yarnpkg.com/unix-dgram/-/unix-dgram-2.0.4.tgz#14d4fc21e539742b8fb027de16eccd4e5503a344"
+  integrity sha512-7tpK6x7ls7J7pDrrAU63h93R0dVhRbPwiRRCawR10cl+2e1VOvF3bHlVJc6WI1dl/8qk5He673QU+Ogv7bPNaw==
+  dependencies:
+    bindings "^1.3.0"
+    nan "^2.13.2"
+
 unixify@1.0.0:
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/unixify/-/unixify-1.0.0.tgz#3a641c8c2ffbce4da683a5c70f03a462940c2090"