diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..cc08445
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,14 @@
+# Drupal editor configuration normalization
+# @see http://editorconfig.org/
+
+# This is the top-most .editorconfig file; do not search in parent directories.
+root = true
+
+# All files.
+[*]
+end_of_line = LF
+indent_style = space
+indent_size = 4
+charset = utf-8
+trim_trailing_whitespace = true
+insert_final_newline = true
diff --git a/.github/workflows/changelog.yaml b/.github/workflows/changelog.yaml
new file mode 100644
index 0000000..15297e3
--- /dev/null
+++ b/.github/workflows/changelog.yaml
@@ -0,0 +1,29 @@
+# Do not edit this file! Make a pull request on changing
+# github/workflows/changelog.yaml in
+# https://github.com/itk-dev/devops_itkdev-docker if need be.
+
+### ### Changelog
+###
+### Checks that changelog has been updated
+
+name: Changelog
+
+on:
+ pull_request:
+
+jobs:
+ changelog:
+ runs-on: ubuntu-latest
+ strategy:
+ fail-fast: false
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v5
+ with:
+ fetch-depth: 2
+
+ - name: Git fetch
+ run: git fetch
+
+ - name: Check that changelog has been updated.
+ run: git diff --exit-code origin/${{ github.base_ref }} -- CHANGELOG.md && exit 1 || exit 0
diff --git a/.github/workflows/composer.yaml b/.github/workflows/composer.yaml
new file mode 100644
index 0000000..17728b8
--- /dev/null
+++ b/.github/workflows/composer.yaml
@@ -0,0 +1,89 @@
+# Do not edit this file! Make a pull request on changing
+# github/workflows/composer.yaml in
+# https://github.com/itk-dev/devops_itkdev-docker if need be.
+
+### ### Composer
+###
+### Validates composer.json and checks that it's normalized.
+###
+### #### Assumptions
+###
+### 1. A docker compose service named `phpfpm` can be run and `composer` can be
+### run inside the `phpfpm` service.
+### 2. [ergebnis/composer-normalize](https://github.com/ergebnis/composer-normalize)
+### is a dev requirement in `composer.json`:
+###
+### ``` shell
+### docker compose run --rm phpfpm composer require --dev ergebnis/composer-normalize
+### ```
+###
+### Normalize `composer.json` by running
+###
+### ``` shell
+### docker compose run --rm phpfpm composer normalize
+### ```
+
+name: Composer
+
+env:
+ COMPOSE_USER: runner
+
+on:
+ pull_request:
+ push:
+ branches:
+ - main
+ - develop
+
+jobs:
+ composer-validate:
+ runs-on: ubuntu-latest
+ strategy:
+ fail-fast: false
+ steps:
+ - uses: actions/checkout@v5
+
+ - name: Create docker network
+ run: |
+ docker network create frontend
+
+ - run: |
+ docker compose run --rm phpfpm composer validate --strict
+
+ composer-normalized:
+ runs-on: ubuntu-latest
+ strategy:
+ fail-fast: false
+ steps:
+ - uses: actions/checkout@v5
+
+ # https://github.com/mxschmitt/action-tmate?tab=readme-ov-file#manually-triggered-debug
+ # Enable tmate debugging if debug logging is enabled (cf.
+ # https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/accessing-contextual-information-about-workflow-runs#runner-context)
+ - name: Setup tmate session
+ uses: mxschmitt/action-tmate@v3
+ with:
+ limit-access-to-actor: false
+ if: 1 == runner.debug
+
+ - name: Create docker network
+ run: |
+ docker network create frontend
+
+ - run: |
+ docker compose run --rm phpfpm composer install
+ docker compose run --rm phpfpm composer normalize --dry-run
+
+ composer-audit:
+ runs-on: ubuntu-latest
+ strategy:
+ fail-fast: false
+ steps:
+ - uses: actions/checkout@v5
+
+ - name: Create docker network
+ run: |
+ docker network create frontend
+
+ - run: |
+ docker compose run --rm phpfpm composer audit
diff --git a/.github/workflows/mago.yaml b/.github/workflows/mago.yaml
new file mode 100644
index 0000000..7522166
--- /dev/null
+++ b/.github/workflows/mago.yaml
@@ -0,0 +1,49 @@
+name: Mago
+
+on:
+ pull_request:
+ push:
+ branches:
+ - main
+ - develop
+
+jobs:
+ # https://mago.carthage.software/latest/en/guide/getting-started/
+ mago:
+ name: Mago
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v5
+
+ - name: Create docker network
+ run: |
+ docker network create frontend
+
+ - run: |
+ docker compose run --rm mago lint
+
+ mago-format:
+ name: Mago - format
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v5
+
+ - name: Create docker network
+ run: |
+ docker network create frontend
+
+ - run: |
+ docker compose run --rm mago format --check
+
+ mago-analyze:
+ name: Mago - analyze
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v5
+
+ - name: Create docker network
+ run: |
+ docker network create frontend
+
+ - run: |
+ docker compose run --rm mago analyze
diff --git a/.github/workflows/markdown.yaml b/.github/workflows/markdown.yaml
new file mode 100644
index 0000000..cdd8b4b
--- /dev/null
+++ b/.github/workflows/markdown.yaml
@@ -0,0 +1,44 @@
+# Do not edit this file! Make a pull request on changing
+# github/workflows/markdown.yaml in
+# https://github.com/itk-dev/devops_itkdev-docker if need be.
+
+### ### Markdown
+###
+### Lints Markdown files (`**/*.md`) in the project.
+###
+### [markdownlint-cli configuration
+### files](https://github.com/igorshubovych/markdownlint-cli?tab=readme-ov-file#configuration),
+### `.markdownlint.jsonc` and `.markdownlintignore`, control what is actually
+### linted and how.
+###
+### #### Assumptions
+###
+### 1. A docker compose service named `markdownlint` for running `markdownlint`
+### (from
+### [markdownlint-cli](https://github.com/igorshubovych/markdownlint-cli))
+### exists.
+
+name: Markdown
+
+on:
+ pull_request:
+ push:
+ branches:
+ - main
+ - develop
+
+jobs:
+ markdown-lint:
+ runs-on: ubuntu-latest
+ strategy:
+ fail-fast: false
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v5
+
+ - name: Create docker network
+ run: |
+ docker network create frontend
+
+ - run: |
+ docker compose run --rm markdownlint markdownlint '**/*.md'
diff --git a/.github/workflows/php.yaml b/.github/workflows/php.yaml
new file mode 100644
index 0000000..7ae804d
--- /dev/null
+++ b/.github/workflows/php.yaml
@@ -0,0 +1,60 @@
+# Do not edit this file! Make a pull request on changing
+# github/workflows/symfony/php.yaml in
+# https://github.com/itk-dev/devops_itkdev-docker if need be.
+
+### ### Symfony PHP
+###
+### Checks that PHP code adheres to the [Symfony coding
+### standards](https://symfony.com/doc/current/contributing/code/standards.html).
+###
+### #### Assumptions
+###
+### 1. A docker compose service named `phpfpm` can be run and `composer` can be
+### run inside the `phpfpm` service. 2.
+### [friendsofphp/php-cs-fixer](https://github.com/PHP-CS-Fixer/PHP-CS-Fixer)
+### is a dev requirement in `composer.json`:
+###
+### ``` shell
+### docker compose run --rm phpfpm composer require --dev friendsofphp/php-cs-fixer
+### ```
+###
+### Clean up and check code by running
+###
+### ``` shell
+### docker compose run --rm phpfpm vendor/bin/php-cs-fixer fix
+### docker compose run --rm phpfpm vendor/bin/php-cs-fixer fix --dry-run --diff
+### ```
+###
+### > [!NOTE] The template adds `.php-cs-fixer.dist.php` as [a configuration
+### > file for PHP CS
+### > Fixer](https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/blob/master/doc/config.rst)
+### > and this makes it possible to override the actual configuration used in a
+### > project by adding a more important configuration file, `.php-cs-fixer.php`.
+
+name: Symfony PHP
+
+env:
+ COMPOSE_USER: runner
+
+on:
+ pull_request:
+ push:
+ branches:
+ - main
+ - develop
+
+jobs:
+ coding-standards:
+ name: PHP - Check Coding Standards
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v5
+
+ - name: Create docker network
+ run: |
+ docker network create frontend
+
+ - run: |
+ docker compose run --rm phpfpm composer install
+ # https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/blob/master/doc/usage.rst#the-check-command
+ docker compose run --rm phpfpm vendor/bin/php-cs-fixer fix --dry-run --diff
diff --git a/.github/workflows/yaml.yaml b/.github/workflows/yaml.yaml
new file mode 100644
index 0000000..ba8ca52
--- /dev/null
+++ b/.github/workflows/yaml.yaml
@@ -0,0 +1,41 @@
+# Do not edit this file! Make a pull request on changing
+# github/workflows/yaml.yaml in
+# https://github.com/itk-dev/devops_itkdev-docker if need be.
+
+### ### YAML
+###
+### Validates YAML files.
+###
+### #### Assumptions
+###
+### 1. A docker compose service named `prettier` for running
+### [Prettier](https://prettier.io/) exists.
+###
+### #### Symfony YAML
+###
+### Symfony's YAML config files use 4 spaces for indentation and single quotes.
+### Therefore we use a [Prettier configuration
+### file](https://prettier.io/docs/configuration), `.prettierrc.yaml`, to make
+### Prettier format YAML files in the `config/` folder like Symfony expects.
+
+name: YAML
+
+on:
+ pull_request:
+ push:
+ branches:
+ - main
+ - develop
+
+jobs:
+ yaml-lint:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v5
+
+ - name: Create docker network
+ run: |
+ docker network create frontend
+
+ - run: |
+ docker compose run --rm prettier '**/*.{yml,yaml}' --check
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..6c7667b
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,8 @@
+###> friendsofphp/php-cs-fixer ###
+/.php-cs-fixer.cache
+###< friendsofphp/php-cs-fixer ###
+
+*.local
+.idea
+composer.lock
+vendor/
diff --git a/.markdownlint.jsonc b/.markdownlint.jsonc
new file mode 100644
index 0000000..0253096
--- /dev/null
+++ b/.markdownlint.jsonc
@@ -0,0 +1,22 @@
+// This file is copied from config/markdown/.markdownlint.jsonc in https://github.com/itk-dev/devops_itkdev-docker.
+// Feel free to edit the file, but consider making a pull request if you find a general issue with the file.
+
+// markdownlint-cli configuration file (cf. https://github.com/igorshubovych/markdownlint-cli?tab=readme-ov-file#configuration)
+{
+ "default": true,
+ // https://github.com/DavidAnson/markdownlint/blob/main/doc/md013.md
+ "line-length": {
+ "line_length": 120,
+ "code_blocks": false,
+ "tables": false
+ },
+ // https://github.com/DavidAnson/markdownlint/blob/main/doc/md024.md
+ "no-duplicate-heading": {
+ "siblings_only": true
+ },
+ // https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/organizing-information-with-collapsed-sections#creating-a-collapsed-section
+ // https://github.com/DavidAnson/markdownlint/blob/main/doc/md033.md
+ "no-inline-html": {
+ "allowed_elements": ["details", "summary"]
+ }
+}
diff --git a/.markdownlintignore b/.markdownlintignore
new file mode 100644
index 0000000..d143ace
--- /dev/null
+++ b/.markdownlintignore
@@ -0,0 +1,12 @@
+# This file is copied from config/markdown/.markdownlintignore in https://github.com/itk-dev/devops_itkdev-docker.
+# Feel free to edit the file, but consider making a pull request if you find a general issue with the file.
+
+# https://github.com/igorshubovych/markdownlint-cli?tab=readme-ov-file#ignoring-files
+vendor/
+node_modules/
+LICENSE.md
+# Drupal
+web/*.md
+web/core/
+web/libraries/
+web/*/contrib/
diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php
new file mode 100644
index 0000000..c23b927
--- /dev/null
+++ b/.php-cs-fixer.dist.php
@@ -0,0 +1,20 @@
+in(__DIR__);
+// … that are not ignored by VCS
+$finder->ignoreVCSIgnored(true);
+
+$config = new PhpCsFixer\Config();
+$config->setFinder($finder);
+
+$config->setRules([
+ '@Symfony' => true,
+]);
+
+return $config;
diff --git a/.prettierrc.yaml b/.prettierrc.yaml
new file mode 100644
index 0000000..bd026a0
--- /dev/null
+++ b/.prettierrc.yaml
@@ -0,0 +1,11 @@
+# This file is copied from config/symfony/yaml/.prettierrc.yaml in https://github.com/itk-dev/devops_itkdev-docker.
+# Feel free to edit the file, but consider making a pull request if you find a general issue with the file.
+
+# https://prettier.io/docs/configuration
+overrides:
+ # https://taskfile.dev/docs/styleguide
+ - files:
+ - "Taskfile.{yml,yaml}"
+ options:
+ tabWidth: 2
+ singleQuote: true
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..c95fdf5
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,10 @@
+# Changelog
+
+All notable changes to this project will be documented in this file.
+
+The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
+and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+
+## [Unreleased]
+
+[Unreleased]: https://github.com/itk-dev/f2-api-client
diff --git a/README.md b/README.md
index 3f64d94..5c1f0d2 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,92 @@
# F2 API client
API client for [The cBrain F2 Platform](https://www.cbrain.com/software-pages/the-f2-platform).
+
+See the [F2 REST API documentation](resources/f2-rest-docs/f2-rest-docs-v13s.html#outline) for details.
+
+## Installation
+
+``` shell
+composer require itk-dev/f2-api-client
+```
+
+## Testing
+
+Edit `.env.local` and set these variables:
+
+``` dotenv
+# .env.local
+F2_API_URI=
+F2_API_USERNAME=
+F2_API_SECRET=
+F2_F2_USERNAME=
+```
+
+Run
+
+``` shell
+docker compose run --quiet --rm phpfpm composer install
+docker compose run --quiet --rm phpfpm php bin/f2-api-client getServiceIndex
+```
+
+to check that you can talk to the F2 API.
+
+> [!NOTE]
+> We'll use `task f2-api-client:run` (cf. [Taskfile.yml](Taskfile.yml)) as a shorthand for running `docker compose run
+> --quiet --rm phpfpm php bin/f2-api-client` (cf. [Development](#development)).
+>
+> Use `task f2-api-client:debug` to debug with Xdebug.
+
+Search cases with
+
+``` shell
+task f2-api-client:run -- caseSearch test
+```
+
+See case details:
+
+``` shell
+task f2-api-client:run -- caseById 2204
+```
+
+## Development
+
+For development (and testing) a couple of useful tasks are defined:
+
+``` text
+* f2-api-client:debug: Debug bin/f2-api-client inside docker compose setup, e.g. `task f2-api-client:debug -- searchCases '{"q": "test", "count": 10}'`
+* f2-api-client:run: Run bin/f2-api-client inside docker compose setup, e.g. `task f2-api-client:run -- searchCases '{"q": "test", "count": 10}'`
+```
+
+---
+
+``` mermaid
+---
+title: F2 Conceptual model
+---
+%% https://mermaid.ai/open-source/syntax/classDiagram.html
+classDiagram
+ Document --> Matter
+ Matter --> CaseFile
+ Party
+ Note --> CaseFile: (only if not related to Matter)
+ Note --> Matter: (only if not related to CaseFile)
+
+ Chat --> Matter
+
+ %% class Item{
+ %% +String title
+ %% }
+ %%
+ %% Item <|-- Document
+ %% Item <|-- Matter
+ %% Item <|-- CaseFile
+```
+
+[F2 REST API, p. 4](resources/f2-rest-docs/f2-rest-docs-v13s.html#4)
+
+---
+
+> The client MUST read the service index at runtime and use it to locate the links it needs.
+
+[F2 REST API, p. 8](./resources/f2-rest-docs/f2-rest-docs-v13s.html#8)
diff --git a/Taskfile.yml b/Taskfile.yml
new file mode 100644
index 0000000..95a1445
--- /dev/null
+++ b/Taskfile.yml
@@ -0,0 +1,116 @@
+# https://taskfile.dev
+
+version: '3'
+
+tasks:
+ default:
+ cmds:
+ - task --list
+ silent: true
+
+ compose:
+ cmds:
+ - docker compose {{.TASK_ARGS}} {{.CLI_ARGS}}
+ internal: true
+
+ composer:
+ desc: Run composer inside docker compose setup, e.g. `task {{.TASK}} -- install`
+ cmds:
+ - task: compose
+ vars:
+ TASK_ARGS: run --rm phpfpm composer {{.TASK_ARGS}}
+
+ coding-standards:apply:
+ - task: coding-standards:apply:composer
+ - task: coding-standards:apply:markdown
+ - task: coding-standards:apply:php
+ - task: coding-standards:apply:yaml
+
+ coding-standards:apply:composer:
+ - task: compose
+ vars:
+ TASK_ARGS: run --rm phpfpm composer normalize
+
+ coding-standards:apply:markdown:
+ - task: compose
+ vars:
+ TASK_ARGS: run --rm markdownlint markdownlint '**/*.md' --fix
+
+ coding-standards:apply:php:
+ - task: compose
+ vars:
+ TASK_ARGS: run --rm phpfpm vendor/bin/php-cs-fixer fix
+
+ coding-standards:apply:yaml:
+ - task: compose
+ vars:
+ TASK_ARGS: run --rm prettier '**/*.{yml,yaml}' --write
+
+ coding-standards:check:
+ - task: coding-standards:check:composer
+ - task: coding-standards:check:markdown
+ - task: coding-standards:check:php
+ - task: coding-standards:check:yaml
+
+ coding-standards:check:composer:
+ - task: coding-standards:apply:composer
+ - task: compose
+ vars:
+ TASK_ARGS: run --rm phpfpm composer normalize --dry-run
+ - task: compose
+ vars:
+ TASK_ARGS: run --rm phpfpm composer validate
+
+ coding-standards:check:markdown:
+ - task: coding-standards:apply:markdown
+ - task: compose
+ vars:
+ TASK_ARGS: run --rm markdownlint markdownlint '**/*.md'
+
+ coding-standards:check:php:
+ - task: coding-standards:apply:php
+ - task: compose
+ vars:
+ TASK_ARGS: run --rm phpfpm vendor/bin/php-cs-fixer fix --dry-run --diff
+
+ coding-standards:check:yaml:
+ - task: coding-standards:apply:yaml
+ - task: compose
+ vars:
+ TASK_ARGS: run --rm prettier '**/*.{yml,yaml}' --check
+
+ # https://mago.carthage.software/latest/en/guide/getting-started/
+ mago:run:
+ desc: 'Run all Mago steps (cf.
+ https://mago.carthage.software/latest/en/guide/getting-started/)'
+ cmds:
+ - task: mago:lint
+ - task: mago:format
+ - task: mago:analyze
+
+ mago:lint: &mago_command
+ desc: 'Run `mago {{.TASK | replace "mago:" "" }}` inside docker compose setup'
+ cmds:
+ - task: compose
+ vars:
+ TASK_ARGS: run --rm mago {{.TASK | replace "mago:" "" }}
+
+ mago:format: *mago_command
+ mago:analyze: *mago_command
+
+ f2-api-client:run:
+ desc: 'Run bin/f2-api-client inside docker compose setup, e.g. `task {{.TASK}}
+ -- searchCases ''{"q": "test", "count": 10}''`'
+ cmds:
+ - task: compose
+ vars:
+ TASK_ARGS: run --quiet --rm phpfpm php bin/f2-api-client
+
+ f2-api-client:debug:
+ desc: 'Debug bin/f2-api-client inside docker compose setup, e.g. `task {{.TASK}}
+ -- searchCases ''{"q": "test", "count": 10}''`'
+ cmds:
+ - task: compose
+ vars:
+ TASK_ARGS: run --quiet --env PHP_XDEBUG_MODE=debug --rm phpfpm php
+ bin/f2-api-client
diff --git a/bin/f2-api-client b/bin/f2-api-client
new file mode 100755
index 0000000..89ba26d
--- /dev/null
+++ b/bin/f2-api-client
@@ -0,0 +1,15 @@
+#!/usr/bin/env php
+addCommand($command);
+
+$application->setDefaultCommand('f2:api:client', true);
+$application->run();
diff --git a/compose.yaml b/compose.yaml
new file mode 100644
index 0000000..ce1f8b9
--- /dev/null
+++ b/compose.yaml
@@ -0,0 +1,43 @@
+services:
+ phpfpm:
+ image: itkdev/php8.3-fpm:latest
+ user: ${COMPOSE_USER:-deploy}
+ profiles:
+ - dev
+ environment:
+ - PHP_XDEBUG_MODE=${PHP_XDEBUG_MODE:-off}
+ - PHP_IDE_CONFIG=serverName=localhost
+ volumes:
+ - .:/app
+ # https://docs.docker.com/compose/how-tos/environment-variables/set-environment-variables/#additional-information-1
+ env_file:
+ - path: .env.local
+ required: false
+
+ # Code checks tools
+ markdownlint:
+ image: itkdev/markdownlint
+ profiles:
+ - dev
+ volumes:
+ - ./:/md
+
+ prettier:
+ # Prettier does not (yet, fcf.
+ # https://github.com/prettier/prettier/issues/15206) have an official
+ # docker image.
+ # https://hub.docker.com/r/jauderho/prettier is good candidate (cf. https://hub.docker.com/search?q=prettier&sort=updated_at&order=desc)
+ image: jauderho/prettier
+ profiles:
+ - dev
+ volumes:
+ - ./:/work
+
+ # https://mago.carthage.software/latest/en/guide/installation/#docker
+ mago:
+ image: ghcr.io/carthage-software/mago
+ profiles:
+ - dev
+ volumes:
+ - ./:/app
+ working_dir: /app
diff --git a/composer.json b/composer.json
index 5832e4a..ceaea40 100644
--- a/composer.json
+++ b/composer.json
@@ -2,5 +2,38 @@
"name": "itk-dev/f2-api-client",
"description": "F2 API client",
"license": "MIT",
- "type": "library"
+ "type": "library",
+ "require": {
+ "ext-simplexml": "*",
+ "symfony/console": "^6.4 || ^7.4",
+ "symfony/http-client": "^6.4 || ^7.4",
+ "symfony/http-foundation": "^6.4 || ^7.4",
+ "symfony/options-resolver": "^6.4 || ^7.4"
+ },
+ "require-dev": {
+ "php": "^8.3",
+ "ergebnis/composer-normalize": "^2.52",
+ "friendsofphp/php-cs-fixer": "^3.95"
+ },
+ "autoload": {
+ "psr-4": {
+ "ItkDev\\F2ApiClient\\": "src/"
+ }
+ },
+ "bin": [
+ "bin/f2-api-client"
+ ],
+ "config": {
+ "allow-plugins": {
+ "ergebnis/composer-normalize": true
+ }
+ },
+ "scripts": {
+ "post-update-cmd": [
+ "@php composer normalize"
+ ],
+ "post-require": [
+ "@php composer normalize"
+ ]
+ }
}
diff --git a/mago.toml b/mago.toml
new file mode 100644
index 0000000..f7f5970
--- /dev/null
+++ b/mago.toml
@@ -0,0 +1,54 @@
+#:schema https://mago.carthage.software/1.27.1/schema.json
+# Welcome to Mago!
+# For full documentation, see https://mago.carthage.software/tools/overview
+version = "1"
+php-version = "8.3.0"
+
+[source]
+workspace = "."
+paths = ["src/"]
+includes = ["vendor"]
+excludes = []
+
+[source.glob]
+literal-separator = true
+
+[formatter]
+print-width = 120
+tab-width = 4
+use-tabs = false
+
+# php-cs-fixer likes these
+empty-line-before-return = true
+method-brace-style = "always-next-line"
+
+# https://mago.carthage.software/latest/en/tools/formatter/configuration-reference/#empty-bodies
+inline-empty-constructor-braces = false
+inline-empty-classlike-braces = false
+
+[linter]
+integrations = []
+
+[linter.rules]
+ambiguous-function-call = { enabled = false }
+literal-named-argument = { enabled = false }
+halstead = { effort-threshold = 7000 }
+
+[analyzer]
+plugins = []
+find-unused-definitions = true
+find-unused-expressions = false
+analyze-dead-code = false
+memoize-properties = true
+allow-possibly-undefined-array-keys = true
+check-throws = false
+unchecked-exceptions = ["Error", "LogicException"]
+unchecked-exception-classes = []
+check-missing-override = false
+find-unused-parameters = false
+strict-list-index-checks = false
+strict-array-index-existence = false
+allow-array-truthy-operand = false
+no-boolean-literal-comparison = false
+check-missing-type-hints = false
+register-super-globals = true
diff --git a/resources/f2-rest-docs/Taskfile.yml b/resources/f2-rest-docs/Taskfile.yml
new file mode 100644
index 0000000..56f91af
--- /dev/null
+++ b/resources/f2-rest-docs/Taskfile.yml
@@ -0,0 +1,19 @@
+# yaml-language-server: $schema=https://taskfile.dev/schema.json
+
+version: '3'
+
+tasks:
+ default:
+ - task --list
+
+ html:generate:
+ desc: Generate HTML from PDF
+ deps:
+ - html:clean
+ cmds:
+ - docker run --volume $PWD:/app --workdir /app --rm minidocks/poppler pdftohtml f2-rest-docs-v13.pdf
+
+ html:clean:
+ desc: Remove all generate HTML stuff
+ cmds:
+ - cmd: rm -f *.{html,png}
diff --git a/resources/f2-rest-docs/f2-rest-docs-v13-23_1.png b/resources/f2-rest-docs/f2-rest-docs-v13-23_1.png
new file mode 100644
index 0000000..2e51ce9
Binary files /dev/null and b/resources/f2-rest-docs/f2-rest-docs-v13-23_1.png differ
diff --git a/resources/f2-rest-docs/f2-rest-docs-v13.html b/resources/f2-rest-docs/f2-rest-docs-v13.html
new file mode 100644
index 0000000..f65a734
--- /dev/null
+++ b/resources/f2-rest-docs/f2-rest-docs-v13.html
@@ -0,0 +1,16 @@
+
+
+
+F2-REST Documentation
+
+
+
+
+
+
+
+
+
diff --git a/resources/f2-rest-docs-v13.pdf b/resources/f2-rest-docs/f2-rest-docs-v13.pdf
similarity index 100%
rename from resources/f2-rest-docs-v13.pdf
rename to resources/f2-rest-docs/f2-rest-docs-v13.pdf
diff --git a/resources/f2-rest-docs/f2-rest-docs-v13_ind.html b/resources/f2-rest-docs/f2-rest-docs-v13_ind.html
new file mode 100644
index 0000000..5dfaf8d
--- /dev/null
+++ b/resources/f2-rest-docs/f2-rest-docs-v13_ind.html
@@ -0,0 +1,194 @@
+
+
+
+
+
+Outline
Page 1
+Page 2
+Page 3
+Page 4
+Page 5
+Page 6
+Page 7
+Page 8
+Page 9
+Page 10
+Page 11
+Page 12
+Page 13
+Page 14
+Page 15
+Page 16
+Page 17
+Page 18
+Page 19
+Page 20
+Page 21
+Page 22
+Page 23
+Page 24
+Page 25
+Page 26
+Page 27
+Page 28
+Page 29
+Page 30
+Page 31
+Page 32
+Page 33
+Page 34
+Page 35
+Page 36
+Page 37
+Page 38
+Page 39
+Page 40
+Page 41
+Page 42
+Page 43
+Page 44
+Page 45
+Page 46
+Page 47
+Page 48
+Page 49
+Page 50
+Page 51
+Page 52
+Page 53
+Page 54
+Page 55
+Page 56
+Page 57
+Page 58
+Page 59
+Page 60
+Page 61
+Page 62
+Page 63
+Page 64
+Page 65
+Page 66
+Page 67
+Page 68
+Page 69
+Page 70
+Page 71
+Page 72
+Page 73
+Page 74
+Page 75
+Page 76
+Page 77
+Page 78
+Page 79
+Page 80
+Page 81
+Page 82
+Page 83
+Page 84
+Page 85
+Page 86
+Page 87
+Page 88
+Page 89
+Page 90
+Page 91
+Page 92
+Page 93
+Page 94
+Page 95
+Page 96
+Page 97
+Page 98
+Page 99
+Page 100
+Page 101
+Page 102
+Page 103
+Page 104
+Page 105
+Page 106
+Page 107
+Page 108
+Page 109
+Page 110
+Page 111
+Page 112
+Page 113
+Page 114
+Page 115
+Page 116
+Page 117
+Page 118
+Page 119
+Page 120
+Page 121
+Page 122
+Page 123
+Page 124
+Page 125
+Page 126
+Page 127
+Page 128
+Page 129
+Page 130
+Page 131
+Page 132
+Page 133
+Page 134
+Page 135
+Page 136
+Page 137
+Page 138
+Page 139
+Page 140
+Page 141
+Page 142
+Page 143
+Page 144
+Page 145
+Page 146
+Page 147
+Page 148
+Page 149
+Page 150
+Page 151
+Page 152
+Page 153
+Page 154
+Page 155
+Page 156
+Page 157
+Page 158
+Page 159
+Page 160
+Page 161
+Page 162
+Page 163
+Page 164
+Page 165
+Page 166
+Page 167
+Page 168
+Page 169
+Page 170
+Page 171
+Page 172
+Page 173
+Page 174
+Page 175
+Page 176
+Page 177
+Page 178
+Page 179
+Page 180
+Page 181
+Page 182
+Page 183
+Page 184
+Page 185
+Page 186
+Page 187
+
+
diff --git a/resources/f2-rest-docs/f2-rest-docs-v13s.html b/resources/f2-rest-docs/f2-rest-docs-v13s.html
new file mode 100644
index 0000000..0b684f2
--- /dev/null
+++ b/resources/f2-rest-docs/f2-rest-docs-v13s.html
@@ -0,0 +1,4018 @@
+
+
+
+
+
+
+F2-REST Documentation
+Created on 08/12/2025 04:54 for F2 version 13
+1
+
+Introduction
+The F2 REST Service is an open API for third party vendors to interact with F2. Through this service
it is possible to read and modify case files, matters, documents, parties and more.
+REST [Fielding] means Representational State Transfer and it is a network architecture designed
for the web. There is a lot to say about REST (and quite a lot of misconceptions too), but for now,
we will just highlight a few of the main points:
+All resources in the system are given their own uniquely identified URL. This means that any
given piece of data in F2 is given its own unique URL where it can be retrieved from.
+Resources have one (or more) externally visible representations which are decoupled from the
actual implementation in F2.
+Resources can be read and modified using the standard HTTP verbs (GET, POST, PUT, DELETE,
PATCH and so on).
+Resources are linked together using hypermedia. A case file contains links to its child matters, a
document contains a link to its creating party and so on.
+There is no up-front documentation of the URL structures. Instead we document link relations –
the names of the links. So for instance we name the link from a case file to its child matters as
"down" and it is then up to the client to extract the relevant link and its target URL at runtime.
+The service has a central service index which contains a list of links to all the top-level
resources. The URL of the service index is the only concrete URL documented. The client must
then extract the required links from the service index using the link relation names published in
this documentation.
+Getting started
+The easiest way to get acquainted with the service is to point a browser to the service index and
start exploring the capabilities from there. The server returns XML with an embedded reference to
an XML style sheet which will transform the XML to nicely formated HTML if the browser supports
it.
+Authentication
+The service supports OAuth2 authentication.
+OAuth2 avoids storing F2 user passwords on the client machine.
+The supported OAuth2 flows are "Resource Owner Password Credentials Grant" (mostly used with
background processing services), "Authorization Code Grant" (mostly used with end user facing
applications) and "Client credentials grant" (which is rarely used).
+It is furthermore possible to get information about the authenticated user with OpenID Connect
[OIDC].
+2
+
+Searching
+Searching is supported by the use of OpenSearch [OpenSearch] documents and F2 custom queries.
See F2-REST Documentation and F2-REST Documentation.
+Structured searching by case numbers, personal identification numbers and such is also possible
as described in F2-REST Documentation and F2-REST Documentation.
+Updating data
+Updating of existing resources is supported via the HTTP verb PATCH using JSON patch documents
[JSONPatch].
+Software developers kit (SDK)
+cBrain has a small SDK for developing C# solutions that interacts with the F2-REST service. The
SDK consists of this manual, a set of classes representing the various F2 resources and some
example code.
+Please contact cBrain for further information about this product.
+3
+
+Conceptual model
+At the very center of F2 we find the "Digital Archive" — a place to store case files, matters and
related documents. In this chapter we give a short introduction to those elements that are exposed
through F2-REST — for a more detailed explanation we recommend reading other parts of the F2
manuals.
+Case files, matters and documents
+The logical structure of a case file consists of digital documents organized in logical documents
called "matters"[1] which again are bundled together in case files:
+Case file =contains many=> Matters =contains many=> Documents
+Digital documents can be of any kind of file format such as Office files, PDF files, zip files, images
and so on.
+A matter often corresponds to some kind of communication — typically an e-mail — with attached
files stored as documents on the matter.
+Parties
+An important part of case management is the parties related to a case or other object. A "party" is
a broad concept that represents a person, an organization, a company or some other legal entity.
+Parties are related to other F2 objects in various ways; a party may be the "owner" of a case file,
the "responsible" for a matter, the "creator" of a document or the "receiver" of an e-mail and so
on.
+In F2 we distinguish between two different versions of a party — the registry version and the
original version. The registry version of a party represents its up-to-date current state whereas the
original version represents the party at the time it was associated with a specific entity in F2 — for
instance when assigned as the receiver of an e-mail.
+Notes
+A note is an informal way to communicate in F2. A note can be attached to either a case or a
matter. The note is visible to all parties who have read access to the given entity to which the note
is attached. A note can have an arbitrary number of text entries, each created by any person who
has access to the note.
+In the case of notes on matters, a number of participants can be added. This results in the matter
being marked as unread for the participants and thus shown in their inbox whenever a new entry is
made.
+1. "Matter" as in "legal matters" ("Akt" in Danish).
+4
+
+Chats
+A chat is an informal way to communicate in F2. A chat can be attached to a matter. At any time, a
chat has a number of assigned participants. A chat can have an arbitrary number of text entries,
each created by any participant of the chat. The chat is only visible to parties who are assigned as
participants of the chat.
+A number of participants can be added dynamically to the chat. This results in the matter
becoming visible (with read access) and marked as unread for the new participants and thus
shown in their inbox whenever a new entry is made.
+Participants can also be removed dynamically. This results in the matter being inaccessible for the
removed participants unless they are granted access by other means.
+Approvals
+Approvals represent the status of approval processes associated with matters.
+Task guides
+Task guides in F2 represents task lists grouped in processes. Tasks can be completed (marked as
complete) as well as "executed" which corresponds to invoking the main operation of a task. For an
in-depth explanation of task guides, please see other appropriate F2 manuals.
+In F2-REST it is possible to read the whole process/task tree with the current visibility and
"completeness" of each task and process — as well as it is possible to complete and execute tasks
and read/update the values of fields in the task guides.
+Extension records and lists
+One of the extension points of F2 allows developers to store named records of data together with
case files — and such records may further more contain lists of other records (which we will call
"rows" to avoid confusion).
+Records
+can
+be
+found
+on
+case
+files
+by
+looking
+for
+the
+link
+relations
+http://cbrain.com/casefile/rel/extension-records and http://cbrain.com/casefile/rel/extension-record-
by-name (see F2-REST Documentation).
+Rows are all identified by a GUID (globally unique identifier) which can be used to reference the
rows when doing update/delete/append operations on lists. F2-REST ensures rows are stored and
retrieved in the sequence they are appended.
+Record names can be chosen freely, but the special name "CaseInfo" is reserved for data stored as
F2 process information ("Sagens oplysninger" in Danish).
+5
+
+It is not possible to embed lists in lists - so in the above case we won’t be able to store the whole
family tree, only one single family.
+Custom XML data
+Another of the extension points of F2 allows developers to associate raw XML data with existing
entities such as case files and matters. The XML document and the entity are associated by a
simple string key and there can be only one XML document associated for each key.
+A case file may for instance have geographical information in GML XML associated to it by the key
"GIS".
+F2 places no restriction on the actual XML stored as custom XML data. Neither does F2 imply any
specific interpretation of the XML.
+Additional properties
+Data in F2 can also be enriched by associating collections of simple key/value pairs with various
objects (usually parties).
+A person (external party) may for instance be related to a job interview and in this context, we
need to store the applicant’s date of birth. This can be stored as a key/value combination where
the key is "DateOfBirth" and the value is the actual date of birth.
+Meetings
+A meeting is defined by start-time, end-time and similar meeting related meta data. It also holds a
list of agenda items with associated documents.
+6
+
+Hypermedia elements
Navigation
+Most of the F2 representations contain links to other resources that represent other parts of F2.
Links are borrowed from the Atom specification [ATOM] and have the same set of attributes.
+Here is an example of a link leading to a resource for creating matters:
+<Link href="..."
rel="http://cbrain.com/casefile/rel/create-matter"
type="text/html"
title="Add matter"/ >
+URL templates
+The service includes URL templates in the style of a URL with replacement parameters embedded
in curly braces — like for instance http://some-host/some-path/{x}/{y} or http://some-
host/some-path?some-parameter={x} .
+URL templates require the client to substitute values for the template parameters and use the
result as a URL for further interaction with the service.
+Example: the URL template http://some-host/some-path/{x}/{y} with x=1 and y=abc
becomes: http://some-host/some-path/1/abc .
+URL templates can be found in the service index (see Service index) and MUST be discovered at
runtime — URLs should never be hard coded in any client code.
+7
+
+Service index
+The service index contains links to all the top level resources in the service. It can be represented
in JSON ( application/json ), ATOM ( application/atom+xml ) or HTML ( text/html ).
+The JSON representation is a single object that maps from link relation names to actual links:
+Example snippet from service index as JSON
+{
"http://cbrain.com/casefile/rel/create-meeting":
{
"href": "http://...",
"title": "Create meeting"
},
"http://cbrain.com/casefile/rel/oauth2-token":
{
"href": "http://...",
"title": "Token endpoint for OAuth2"
}
}
+The HTML version uses anchor elements <a> to represent links and the "rel" attribute for
identifying link relations:
+Example snippet from service index as HTML
+<html xmlns="http://www.w3.org/1999/xhtml">
<body>
<dl>
+ <dt>
<a href="http://localhost/f2-restservice-4.3/meeting-create"
rel="http://cbrain.com/casefile/rel/create-meeting">Create meeting
</a>
</dt>
<dd>URL for creating new meetings.</dd>
+ <dt>
<a href="http://localhost/f2-restservice-4.3/oauth2/token"
rel="http://cbrain.com/casefile/rel/oauth2-token">OAuth2 Token endpoint
</a>
</dt>
<dd>Token endpoint for OAuth2 according to RFC 6749</dd>
+ </dl>
</body>
+The client MUST read the service index at runtime and use it to locate the links it needs.
+Some elements in the service index are URL templates (see Hypermedia and URL templates) and
require further handling by the client before use.
+8
+
+Date and time
+Date and time fields in F2 are generally stored without any kind of time zone indication — and it is
the responsibility of the client application to apply the right time zone transformations when
reading and writing data in F2. This is normally taken care of automatically by the desktop client
and other standard cBrain applications — but with F2-REST the client application must be aware of
this issue.
+This means the client must know the time difference between the server’s UTC offset and its own
UTC offset — and apply this offset when reading and writing dates and times.
+The recommendation for dates like a deadline is to leave out any time-part and set it to 00:00:00.
+Daylight savings
+Clients using F2-REST should be aware of daylight savings and take this into account when reading
and writing dates and times. If the client and server operate in the same time zone then there is
nothing special to do as both will change their UTC time zone offset simultaneously — otherwise
the client must take daylight savings into account.
+Most application programming languages, like for instance C#, have built-in functions for applying
time zone differences when server and client time zones are known.
+Usually it is not necessary to handle daylight savings in any specific way, as F2 works with dates
only and no time-part in all input fields (such as a deadline).
+Be aware that some date and time combinations are invalid — like when skipping from 02:00 to
03:00 when changing to summertime — and some combinations occur twice when skipping from
03:00 to 02:00. Similarly, some days last 23 hours only while others last 25 hours. Never try to add
days by simply adding 24 hours!
+String format
+The standard string format is YYYY-MM-DD'T'HH:MM:SS with no time zone designator. This
corresponds to the ISO 8601 date time format with unqualified local time zone. Leaving out the
time zone designator ensure that the F2-REST server accepts the value without any server-side
transformations.
+It is although possible to include time zone designators but the actual result is undocumented and
unsupported as it goes through various server side transformations that are difficult to control.
+XML format for extension records
+When working with extension records for task guide data, date and time values are represented
using standard XML formatting rules. This means the value must have the attribute xsi:type set
to "xsd:dateTime" and use the format YYYY-MM-DD'T'HH:MM:SS+/-hh:mm .
+9
+
+Extension records are, unlike standard F2 fields such as a matter’s deadline, stored as-is in an XML
blob in the database. The only exception here is that date and time values without a time zone
designator will be assigned the time zone offset of the server.
+Beware that the desktop client’s date and time handling for extension records works differently
from other date and time fields in F2 with respect to time zones. At the time of writing it will store
time zone differences, including hours, in the database, whereas the standard F2 fields strip the
hours from the time stamps.
+Example
+Consider a Danish company with clients operating from both Denmark and New York. The company
decides that the server time zone is Central European with a standard UTC offset of +1 and +2
when daylight savings apply.
+A client in Denmark, reading and writing dates and times from F2-REST, need not apply any time
zone transformations as it operates in the same time zone as the server.
+A client in New York, reading and writing dates and times from F2-REST, needs to apply time zone
transformations though: New York belongs to the Eastern Time Zone which is UTC-5, so the time
zone difference is "Server minus client time zone offsets" which is +1 minus -5 = 6. This means the
client has to add 6 hours when reading dates and times from F2-REST — and it has to subtract 6
hours when writing dates and times.
+If the time-part is irrelevant, such as for a deadline, the client should always send the desired date
with 00:00:00 as the time part — regardless of daylight settings as well as time zone differences.
+10
+
+Data manipulation
+The F2-REST service enables clients to add new content to F2 as well as modify existing data. New
content is usually added using a Post Once Exactly technique (see below). Existing data is modified
using the HTTP verb PATCH together with JSON Patch documents [JSONPatch].
+Post Once Exactly semantics
+Some data manipulation in F2 has "Post Once Exactly" (POE) semantics meaning the operation can
safely be repeated in case of network failures or timeouts.
+POE works by first requesting a POE resource (identified by a URL created by the server) and then
POSTing the actual payload data to that URL. Should the second POST fail due to a timeout or
other problems then it is safe to repeat the exact same POST again and again until it succeeds. It
goes like this:
+1. The client GETs a representation of some entity — for instance a case file or the service index.
+2. The client finds the POE link in the returned representation by looking for a link relation marked
+as http://cbrain.com/casefile/rel/create-matter (or similar).
+3. The client issues an empty POST to the POE link. The content-type should be application/x-
+www-form-urlencoded .
+4. The server responds with a status code 303 (See other) and includes a URL for the new POE
+resource in the Location header.
+5. The client prepares the actual payload and POSTs it to the new POE resource.
+A POE operation that succeeds returns status code 201 "Created". A repeated POE operation that
has succeeded already returns the status code 303 "See other". In both cases the "Location"
header is set to the URL of the created resource.
+Once a POE URL has been obtained by the client it can POST data for a new entity to that URL. The
data can be formatted using the media type
+application/x-www-form-urlencoded ,
+application/json [JSON] or multipart/form-data [MultipartFormdata].
+POE resources are automatically reclaimed by the server after some time and deleted.
+JSON patch documents
+A JSON patch document [JSONPatch] consists of a JSON array of patch operations like add ,
+replace and remove . The server interprets each of these operations and applies them to the
+target resource. Currently, only the replace operation is in use in F2 REST.
+The use of PATCH in this way allows the client to easily perform partial updates of resources (as
opposed to issuing a PUT of the complete resource).
+11
+
+Example
+PATCH /target HTTP/1.1
Content-Type: application/json-patch
+[
{ "op":"replace", "path":"/Type", "value":"Outbound" },
{ "op":"replace", "path":"/Title", "value":"Changed title" },
{ "op":"replace", "path":"/Text", "value":"Changed text" }
]
+Updating parties
+Single party
+A single party, such as the responsible of a case or matter, must be updated by replacing the party
with a new party, using a party reference to indicate which party to use (see F2-REST
Documentation).
+As an example, consider the responsible party of a matter. An HTTP GET on a matter resource
returns something like the following structure:
+Matter example
+<Matter xmlns="http://cbrain.com/casefile/schema/">
<Id>378052</Id>
<Responsible>
<Name>Lise Nielsen</Name>
<PartyNumber>118</PartyNumber>
</Responsible>
</Matter>
+Updating the responsible is simply a matter of patching /Responsible with a suitable party
reference:
+Patch example
+PATCH /some-path HTTP/1.1
Accept: application/vnd.cbrain.casefile+xml
Content-Type: application/json-patch
+[
{"value":{"PartyNo":26},"op":"replace","path":"/Responsible"}
]
+Lists of parties
+Lists of parties, such as receivers and involved parties on cases and matters, must be updated by
replacing the complete party list with a whole new list of parties — it is not possible to update
single elements in the lists.
+12
+
+As an example, consider the involved parties of a matter. An HTTP GET on a matter resource
returns something like the following structure:
+Matter example
+<Matter xmlns="http://cbrain.com/casefile/schema/">
<Id>378052</Id>
<InvolvedParties>
<InvolvedParty>
<Name>Party A</Name>
<PartyNumber>118</PartyNumber>
</InvolvedParty>
<InvolvedParty>
<Name>Party B</Name>
<PartyNumber>75</PartyNumber>
</InvolvedParty>
</InvolvedParties>
</Matter>
+Updating the list of involved parties, is simply a matter of patching /InvolvedParties with suitable
party references (in this case party numbers 26 and 28):
+Patch example
+PATCH /some-path HTTP/1.1
Accept: application/vnd.cbrain.casefile+xml
Content-Type: application/json-patch
+[
{"value":[{"PartyNo":26},{"PartyNo":28}], "op":"replace", "path":"/InvolvedParties"}
]
+13
+
+Encoding rules for input data
+Parameters for the creation of new resources or invoking complex business operations, are
encoded using standard media types — either form-url-encoded, multipart-form-data or JSON.
+Application/x-www-form-urlencoded
+Basic values are encoded as key/value properties following the rules of application/x-www-form-
urlencoded.
+List values are encoded by adding an array index to the keys (prefixed with a colon). So for
instance, a list of three different names and e-mails would be encoded as the following keys:
+Example list encoding using colon for index indicator
+Name:0
EMail:0
Name:1
EMail:1
Name:2
EMail:2
+Example (simple properties)
+Name=John%20Doe&EMail=jd%40example.com
+Example (list properties — %3a is a URL encoded colon)
+Name%3a0=John&Name%3a1=Pete
+Multipart/form-data
+Basic values are encoded as key/value properties following the rules of multipart/form-data
[MultipartFormdata].
+List values are encoded by adding an array index to the keys (prefixed with a colon) in the same
was as it is done for application/x-www-form-urlencoded.
+14
+
+Example
+Content-type: multipart/form-data, boundary=AaB03x
+--AaB03x
content-disposition: form-data; name="Name"
+John Doe
--AaB03x
content-disposition: form-data; name="EMail"
+jd@example.com
--AaB03x
content-disposition: form-data; name="Photo"; filename="some-photo.jpg"
Content-Type: image/jpeg
Content-Transfer-Encoding: binary
+... binary data ...
--AaB03x--
+Application/json
+Basic values are encoded using JSON objects.
+Example
+{
"Name" : "John Doe",
"EMail" : "jd@example.com"
}
+Lists are encoded using JSON arrays.
+Example
+[
{
"Name" : "John Doe",
"EMail" : "jd@example.com"
},
{
"Name" : "Pete",
"EMail" : "pete@example.com"
}
]
+15
+
+Error handling
+F2-REST makes extensive use of standard HTTP codes to flag error conditions — but also adds an
additional payload with more detailed information about the error.
+The payload for error conditions is a document having a single Message element, an optional
+Details element, an optional ReasonCode and optionally an array of links related to the error
+condition.
+Example XML response
+HTTP/1.1 404 Not Found
Content-Length: 356
Content-Type: application/vnd.cbrain.casefile+xml
+<Error xmlns="http://cbrain.com/casefile/schema/">
<Message>Party snapshot with ID 200391 not found.</Message>
<ReasonCode>DossierCaseClosed</ReasonCode>
</Error>
+Example JSON response
+HTTP/1.1 404 Not Found
Content-Length: 65
Content-Type: application/json
+{
"Message":"Party with ID 200391 not found.",
"ReasonCode":"DossierCaseClosed",
"Links":[]
}
+While the Message element will contain a description of the problem, an optional Details element
may contain a more technical description primarily targeted at developers.
+Table 1. Error data properties
+Name
+Description
+Message
+string
General description of the problem. This may be presented to the end-user.
+Details
+string
Technical details about the problem. This should be logged by the client.
+ReasonCode
+string
See ReasonCode below.
+Link
+List of Link
One or more links to other related resources.
+The following is a list of the HTTP status codes used (but clients MUST be prepared to receive other
status codes as infrastructure components such as web proxies may return other codes):
+16
+
+Table 2. HTTP status codes
+Code
+Text
+Description
+200
+OK
+Success.
+201
+Created
+The request has been fulfilled and resulted in a new resource being
created.
+303
+See other
+The response to the request can be found under another URI using
a GET method. When received in response to a POST (or
PUT/DELETE), it should be assumed that the server has received
the data and the redirect should be issued with a separate GET
message.
+400
+Bad request
+The server cannot or will not process the request due to something
that is perceived to be a client error. Usually this is due to a
validation error of some sort — for instance required values that
are missing in a request. See the XML payload for further details
about why the request failed.
+401
+Unauthorized
+Similar to 403 Forbidden, but specifically for use when
authentication is required and has failed or has not yet been
provided.
+403
+Forbidden
+The request was valid but did not have the right authorization to
access the resource.
+404
+Not found
+The requested resource could not be found. See the XML payload
for further details about why the request failed.
+409
+Conflict
+Indicates that the request could not be processed because of
conflict in the request. Most often this is caused by updating a
resource which is in a state that does not allow the update.
+423
+The resource
+Indicates that the request could not be processed because another
+being
+user has locked access to the resource – most likely because it is
+accessed is
+opened for edit in the desktop client. The client should retry the
+locked.
+request again at a later time. The ReasonCode may indicate why
the resource was locked.
+500
+Internal server
+Something is broken. Please contact your local F2 service provider.
+error
+503
+Service
+Indicates that the server might be overloaded or simply out-of-
+unavailable
+service for a while. Common transient reasons are database
deadlocks and timeouts. The client should retry the request again
at a later time.
+ReasonCode
+Often the HTTP status code is not enough to identify the reason for an error. The Message element
may tell exactly what is wrong but it is not easy to react on programmatically. The ReasonCode
+17
+
+may then provide some useful information. ReasonCode value is a string. Note that ReasonCode is
optional.
+These are the registered reason codes:
+Table 3. ReasonCode values
+Code
+Description
+DossierBadCaseNumber
+Operation on a Matter failed because of bad format of a case
number.
+DossierBadCPR
+… because of bad format of the CPR.
+DossierBadResponsible
+… because of bad specification of the Responsible.
+DossierBadTitle
+… because of bad format of the Title.
+DossierCaseClosed
+… because the case is closed.
+DossierCaseNotFound
+… because the case is not found.
+DossierDocumentNotFound
+… because a document is not found.
+DossierDocumentNoWriteAccess
+… because a document is not accessible for writing.
+DossierNoReadAccess
+… because it is not accessible for reading.
+DossierNoResponsible
+… because of missing Responsible.
+DossierNotFound
+… because it is not found.
+DossierNoWriteAccess
+… because it is not accessible for writing.
+DossierOnMeeting
+… because it is located on a meeting.
+Locked
+Operation failed because the resource was locked (primary reason
being cases transferred to external archive and then locked).
+LockedByAnotherUser
+Operation failed because a resource was locked by another user
(typically because someone is editing it).
+CaseClosed
+Operation on a Case failed it is closed.
+Retries
+If a request to F2-REST fails for some reason, the client may retry that request again at a later
time — but care must be taken to avoid duplicate inserts. To avoid duplicates, F2-REST uses a Post-
Once-Exactly technique as described in [Data manipulation].
+Typical error scenarios that should be solved by retrying requests are:
+Network failures: these happen once in a while and will often result in HTTP timeouts or broken
connections as seen from the client application.
+18
+
+Database deadlocks and timeouts: these can be expected when the database server is under
heavy load. These situations are indicated by status code 503 Service Unavailable.
+Locking: some resources can be locked for editing by other users. When trying to modify such a
resource the server returns 423 Locked.
+19
+
+Authentication
+F2-REST supports OAuth2 authentication [OAuth].
+OAuth2 allows the client to authenticate without knowing the F2 user password, and thus the
password will never be stored in any program or configuration file related to the client.
+20
+
+Resource Owner Password Credentials
Grant
+The "Resource Owner Password Credentials Grant" flow is designed for background services
authorizing as specific F2 users.
+In this flow the client sends its own client credentials together with the F2 user name and,
optionally, the F2 user password (see section 4.3 in OAuth).
+To use OAuth2 in this way the client must do as follows:
+1. Register a client ID and client secret. These can be obtained from your local F2 service
+provider.
+2. Request an access token:
+a. Create a HTTP Basic authentication header using the client ID and client secret.
+b. Get the access token endpoint URL from the service index. It is named as
+http://cbrain.com/casefile/rel/oauth2-token .
+c. Make a POST request to the access token endpoint with the following parameters added to
+the payload and encoded using application/x-www-form-urlencoded :
+i. grant_type = "password"
+ii. username = "F2 user name"
+iii. password = "F2 user password" (optional)
+iv. organization_partyno = "F2 organization party number" (optional).
+The organization_partyno parameter is relevant for users with roles in more than one
organization and it allows the client to specify which of the user’s organizations to log in
to using the party number of that organization.
+d. The response will be a JSON encoded representation of a "bearer" token to be used in the
+following requests.
+3. Make a request using the bearer token.
+a. Create a HTTP Authorization header with the value "Bearer" plus the actual bearer token
+returned from the access token request.
+b. Make a request to the required resource.
+Example access token request from the OAuth2 specification
+POST /token HTTP/1.1
+Host: server.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded
+grant_type=password&username=johndoe&password=A3ddj3w
+21
+
+Example access token response from the OAuth2 specification:
+HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache
+{
"access_token":"2YotnFZFEjr1zCsicMWpAA",
"token_type":"bearer",
"expires_in":3600,
"refresh_token":"vKUuy1LYYptqmOYMp806"
}
+Example resource request
+GET /resource HTTP/1.1
Host: server.example.com
Authorization: Bearer 2YotnFZFEjr1zCsicMWpAA
+22
+
+
+Authorization Code Grant
+The "Authorization Code Grant" flow is used when a client needs to make requests on behalf of a
user without knowing any of the user’s credentials. Typically, this is used for scenarios where a
third party application interacts with F2-REST in the context of the end user.
+This flow is a multi-step flow that works as described below (see also section 4.1 in OAuth).
+1. The client starts by redirecting the user agent (typically a web browser) to a predefined
+authorization URL.
+OBS: The client is only a "client" in terms of OAuth2 — typically it is implemented as a server
side component capable of sending redirects to a web browser.
+2. The end user interacts with the authorization server in order to prove his/her identity (for
+instance by using Kerberos or Windows AD Single Sign On).
+3. The authorization server redirects the user agent back to the original client with an
+authorization code in the URL. The client extracts the authorization code.
+4. The client exchanges the authorization code for an access token by calling a predefined token
+handler URL.
+5. The access token is used in sub-sequent calls to F2-REST as a bearer token that enables the
+client to work on behalf of the end user.
+To use this authorization flow with Windows AD Single Sign On (supported by F2) the client must do
as follows:
+1. Register client and callback URL with your local F2 service provider.
+2. Request an authorization code
+23
+
+a. Get the authorization code endpoint URL from the F2-REST service index. It is named as
+http://cbrain.com/casefile/rel/oauth2-adsso-authorization .
+b. Add the following parameters to the authorization code endpoint URL:
+i. response_type =code
+Hard coded value.
+ii. client_id =<client ID>
+Insert OAuth2 client identifier here.
+iii. state =<client state> (optional)
+Insert some client state here to avoid Cross-Site Request Forgery (see section 10.12 in
OAuth).
+iv. redirect_uri =<redirect URL> (optional)
+Insert redirection URL here if more than one is possible — otherwise leave out this
parameter as the authorization service will be configured with it anyway.
+v. scope = <list of requested scopes> (optional)
+Insert space delimited list of requested scopes. Currently only used for OpenID Connect
(with scopes "openid" and "profile").
+c. Redirect the browser to the resulting URL.
+d. After user authorization the browser will be redirected back to the redirect URL.
+e. The redirection handler extracts the authorization "code" value from the URL.
+3. Request an access token
+a. Get the access token endpoint URL from the service index. It is named as
+http://cbrain.com/casefile/rel/oauth2-token .
+b. Make a POST request to the access token endpoint using HTTP Basic Authentication to
+authenticate the client (using the client ID and client secret). Add the following parameters
to the payload and encode them using application/x-www-form-urlencoded :
+i. grant_type =authorization_code
+Hard coded value.
+ii. code =<authorization code>
+Insert authorization code here.
+iii. redirect_uri =<redirect URL>
+If a redirect URL was used in the previous steps then it must be included here again.
+c. If the access token request is valid and authorized, the authorization server issues an access
+token and returns it in a JSON response.
+4. Make a request using the bearer token.
+a. Create an HTTP Authorization header with the value "Bearer" plus the actual bearer token
+returned from the access token request.
+b. Make a request to the required resource using the aquired bearer token.
+24
+
+Example authorization request
+GET /authorize?
response_type=code&client_id=s6BhdRkqt3&state=xyz&redirect_uri=https%3A%2F%2Fclient%2Eexample%
2Ecom%2Fcb HTTP/1.1
Host: server.example.com
+Example authorization response
+HTTP/1.1 302 Found
Location: https://client.example.com/cb?code=SplxlOBeZQQYbYS6WxSbIA&state=xyz
+Example access token request
+POST /token HTTP/1.1
Host: server.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded
+grant_type=authorization_code&code=SplxlOBeZQQYbYS6WxSbIA&redirect_uri=https%3A%2F%2Fclient%2E
example%2Ecom%2Fcb
+Example access token response
+HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
+{
"access_token":"2YotnFZFEjr1zCsicMWpAA",
"token_type":"bearer",
"expires_in":3600,
"refresh_token":"vKUuy1LYYptqmOYMp806"
}
+Example resource request
+GET /resource HTTP/1.1
Host: server.example.com
Authorization: Bearer 2YotnFZFEjr1zCsicMWpAA
+25
+
+F2 Session Grant
+The "F2 Session Grant" flow is used when a client needs to make requests on behalf of a user and
is in possession of a F2-client session ID. Typically, this is used for scenarios where a third party
application interacts with F2-REST in the context of the end user through a "WebPush" task in the
task guide framework.
+To use this flow the client must obtain an F2 session ID and use it as follows:
+1. Register a client ID and client secret. These can be obtained from your local F2 provider.
+2. Request an access token:
+a. Create a HTTP Basic authentication header using the client ID and client secret.
+b. Get the access token endpoint URL from the service index. It is named as
+http://cbrain.com/casefile/rel/oauth2-token .
+c. Make a POST request to the access token endpoint with the following parameters added to
+the payload and encoded using application/x-www-form-urlencoded :
+i. grant_type = "http://cbrain.com/casefile/f2session-grant/"
+ii. f2session_id = <F2 session ID>
+iii. The response will be a JSON encoded representation of a "bearer" token to be used in the
+following requests.
+iv. The bearer token can now be used for resource requests as described in the previous
+sections.
+Example access token request
+POST /token HTTP/1.1
+Host: server.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded
+grant_type=http%3A%2F%2Fcbrain.com%2Fcasefile%2Ff2session-grant%2F&f2session_id=xxxxxxx
+Example access token response
+HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache
+{
"access_token":"2YotnFZFEjr1zCsicMWpAA",
"token_type":"bearer",
"expires_in":3600,
"refresh_token":"vKUuy1LYYptqmOYMp806"
}
+26
+
+JWT Identity Ioken Grant
+The "Identity token Grant" flow is used when a client needs to make requests on behalf of a user
and is in possession of a JWT identity token from a third party identity provider.
+Typically, this is used for scenarios where a third party application authenticates with an external
identity provider, receives and validates a JWT identity token and then forwards the same identity
token to F2-REST for authentication.
+To use this flow the client must obtain an identity token and use it as follows:
+1. Register a client ID and client secret. These can be obtained from your local F2 service
+provider.
+2. Request an access token:
+a. Create an HTTP Basic authentication header using the client ID and client secret.
+b. Get the access token endpoint URL from the service index. It is named as
+http://cbrain.com/casefile/rel/oauth2-token .
+c. Make a POST request to the access token endpoint with the following parameters added to
+the payload and encoded using application/x-www-form-urlencoded :
+i. grant_type = "http://cbrain.com/casefile/identitytoken-grant/"
+ii. id_token = <identity token>
+d. The response will be a JSON encoded representation of a "bearer" token to be used in the
+following requests.
+3. The bearer token can now be used as described in the previous sections.
+Example access token request
+POST /token HTTP/1.1
+Host: server.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded
+grant_type= http%3A%2F%2Fcbrain.com%2Fcasefile%2Fidentitytoken-grant%2F&id_token=xxxxxxx
+27
+
+Example access token response
+HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache
+{
"access_token":"2YotnFZFEjr1zCsicMWpAA",
"token_type":"bearer",
"expires_in":3600,
"refresh_token":"vKUuy1LYYptqmOYMp806"
}
+28
+
+OpenID Connect
+F2-REST support authorization using OpenID Connect as described in [OIDC].
+OpenID Connect is an identity layer on top of the OAuth 2.0 protocol. It allows Clients to verify the
identity of the End-User based on the authentication performed by an Authorization Server, as well
as to obtain basic profile information about the End-User in an interoperable and REST-like manner.
+The OpenID Connect flow is identical to the "Authorization Code Grant" flow — with the addition of
a few OpenID Connect parameters being included. The differences are:
+1. Include the scopes "openid" and "profile" in the "Authorization code request" to get profile
+information about the authenticated user.
+2. The profile information is returned in the access token response as an ID Token (per the OpenID
+Connect specification).
+a. The access token request URL is not the same as for the Authorization Code Grant.
+b. Get the OpenID Connect access token endpoint URL from the service index. It is named as
+http://cbrain.com/casefile/rel/oauth2-idtoken .
+c. Make an access token request to the access token endpoint.
+d. If the access token request is valid and authorized, the authorization server issues an access
+token and returns a response with an ID Token.
+It is not possible to request the ID Token at a later time — it is only available during the
authorization process.
+Example authorization code request
+GET /authorize?
response_type=code&client_id=s6BhdRkqt3&state=xyz&redirect_uri=https%3A%2F%2Fclient%2Eexample%
2Ecom%2Fcb&scope=openid%20profile HTTP/1.1
+Example access token request
+GET /authorize?
response_type=code&client_id=s6BhdRkqt3&state=xyz&redirect_uri=https%3A%2F%2Fclient%2Eexample%
2Ecom%2Fcb&scope=openid%20profile HTTP/1.1
Host: server.example.com
+29
+
+Example access token response
+HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
+{
"access_token":"2YotnFZFEjr1zCsicMWpAA",
"token_type":"bearer",
"expires_in":3600,
"id_token": "... JWT data ..."
}
+30
+
+Refresh tokens
+F2-REST supports refresh tokens as described in section 6 in [OAuth]. For this, the OAuth2
authorization flows mentioned in the previous sections returns "refresh_token" in addition to
"access_token".
+Please notice that refresh tokens have a limited lifetime (default is 24 hours more than the access
token). This means clients should be prepared to handle a situation where both the access token
and the refresh tokens have expired.
+The refresh token can be used later to obtain a new access token with these steps:
+1. Create a HTTP Basic authentication header using the client ID and client secret.
+2. Get the access token endpoint URL from the service index. It is named as
+http://cbrain.com/casefile/rel/oauth2-token .
+3. Make a POST request to the access token endpoint with the following parameters added to the
+payload and encoded using application/x-www-form-urlencoded :
+a. grant_type = "refresh_token"
+b. refresh_token = <refresh token>
+4. The response will be a JSON encoded representation of a "bearer" token to be used in the
+following requests.
+5. The bearer token can now be used as described in the previous sections — as well as the new
+refresh token can be used later on.
+Example access token request
+POST /token HTTP/1.1
+Host: server.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded
+grant_type=refresh_token&refresh_token=vKUuy1LYYptqmOYMp806
+Example access token response
+HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache
+{
"access_token":"SC5b5LyGyqCN6UhaTeuC",
"token_type":"bearer",
"expires_in":3600,
"refresh_token":"VR0UC6H2tNEpcxSfTxUf"
}
+31
+
+OAuth 2.0 Token Introspection
+F2-REST supports RFC 7662 "OAuth 2.0 Token Introspection" (see OAuthTokenInspection). This
standard allows a client to send a POST request to F2-REST, containing an access token, and
retreive some meta information about the token.
+The returned values are:
+Table 4. OAuth2 token introspection response values
+Name
+Description
+active
+bool
True if the access token is active.
+client_id
+string
Client identifier for the OAuth 2.0 client that requested this token.
+exp
+int
Integer timestamp, measured in the number of seconds since January 1
1970 UTC, indicating when this token will expire.
+username
+string
The F2 username associated with the token.
+organization_partyno
+int
Party number of the organization selected during login. This is relevant in
cases where a user is member of more than one organization.
+Get the access token endpoint URL from the service index. It is named as
+http://cbrain.com/casefile/rel/oauth2-token-introspection .
+Example token inspection request
+POST /introspect HTTP/1.1
Host: server.example.com
Accept: application/json
Content-Type: application/x-www-form-urlencoded
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
+token=mF_9.B5f-4.1JqM
+32
+
+Example token inspection response
+HTTP/1.1 200 OK
Content-Type: application/json
+{
"active": true,
"client_id": "l238j323ds-23ij4",
"username": "jdoe",
"organization_partyno": 99,
"exp": 1419356238,
}
+ Common data types
= Links
+Link data type
+The Link data type represents a relation between two resources. Links can be found in most, if not
all, resources represented in F2-REST and is used to indicate related resources such as a
parent/child relationship or a related command processing resource.
+Table 5. Link properties
+Name
+Description
+rel
+string
Link relation identifier.
+href
+string
Actual URL to target resource.
+type
+string
Expected media type of target resource (optional).
+title
+string
Human readable title of link (optional).
+Link example
+<Link href="..."
rel="http://cbrain.com/casefile/rel/enum-type"
title="Enumeration type"/>
+33
+
+Enumerations
+F2 uses a lot of different enumeration types for keywords and various other domain specific codes
in the representations of F2 data such as matters and cases.
+EnumerationItem data type
+The value of a single enumeration property on a F2 object is represented as an object itself with
the following properties:
+Table 6. EnumerationItem properties
+Name
+Description
+Title
+string
Displayed title of selected enumeration value.
+Path
+string
Path in the enumeration value hierarchy.
+Code
+string
Identifier for the selected enumeration value.
+Abbreviation
+string
Abbreviation of selected enumeration’s title. For historical reasons, the
abbreviation can be used as an alternative to the Code property when looking
up enumeration values.
+Link
+List of Link
One or more links to other related resources.
+The Link property may contain a link to the enumeration type definition as indicated by the link
relation http://cbrain.com/casefile/rel/enum-type . The target will be an enumeration type
resource as described in F2-REST Documentation.
+Enumeration example
+<Case>
…
<Keyword>
<Title>00.03.04 - Regionaludvikling EU</Title>
<Path>Parent1Title/Parent2Title/ItemTitle</Path>
<Code>00.03.04</Code>
<Abbreviation>00.03.04</Abbreviation>
<Link href="..."
rel="http://cbrain.com/casefile/rel/enum-type"
title="Enumeration type"/>
</Keyword>
</Case>
+34
+
+Party related data types
PartyItem data type
+A party item represents the primary keys of a single party in a collection of parties.
+Table 7. PartyItem properties
+Name
+Description
+Name
+string
Displayed name of party.
+EMail
+string
Contact e-mail.
+Type
+string
Party type (see below).
+Id
+int
Internal identifier of party - not visible in F2.
+PartyNumber
+int
Internal identifier of party - displayed in F2 party details window.
+SynchronizationKey
+string
Identifier for synchronizing parties with external repositories such as Windows
Active Directory.
+CPRCVR
+string
Personal security number or VAT number.
+CVR_P
+string
Danish P-number extension to CVR (VAT) number.
+The name PartyItem is used to avoid confusion with the resource type Party . For example, the
+Responsible element (found as a sub-element of the Matter resource) is a PartyItem as shown in
+the following example. The link to "self" in the PartyItem is a link to a Party resource (see F2-
REST Documentation).
+Possible values for Type are:
+35
+
+Table 8. Party type values
+Value
+Party type
+User
+F2 user.
+Unit
+F2 organization.
+Team
+F2 team.
+External
+Shared external contact (such as e-mail recipients).
+DistributionList
+F2 distribution list.
+Private
+Private external contact.
+PartyItem Example
+<Responsible>
<Name>Emma Terkelsen</Name>
<EMail>et@example.com</EMail>
<Link href=""..."" rel="self"/>
<Type>User</Type>
<Id>2156</Id>
<PartyNumber>20</PartyNumber>
<CPRCVR>12344321</CPRCVR>
<CVR_P>1234554321</CVR_P>
</Responsible>
+AccessPartyItem data type
+The AccessPartyItem represents a single party with a specific access right to a matter or case. It
contains the same properties as PartyItem along with an Access property, which describes the
user’s access to the containing object.
+Access may either be "Read", "WriteDocument" or "Write".
+AccessPartyItem example
+<Responsible>
<Name>Emma Terkelsen</Name>
<EMail>et@example.com</EMail>
<Link href="..." rel="self"/>
<Type>User</Type>
<Id>2156</Id>
<PartyNumber>20</PartyNumber>
<CPRCVR>12344321</CPRCVR>
<CVR_P>1234554321</CVR_P>
<Access>Read</Access>
</Responsible>
+36
+
+PartyGroupItem data type
+A PartyGroupItem represents a named group of parties (in a collection of PartyGroupItem ).
+PartyGroupItem example
+<Stakeholders>
<PartyGroup>
<Name>My party group</Name>
<SynchronizationKey>C8163116-7031-47FA-9D54-0E6880827B4D</SynchronizationKey>
<PartyNumber>117</PartyNumber>
</PartyGroup>
</Stakeholders>
+PartyReference data type
+Some updates require one or more party references to specify Party resources in requests. A party
reference can be one of many things — an e-mail, a party number, login name and more.
+37
+
+Table 9. PartyReference properties
+Name
+Description
+EMail
+string
Exact e-mail. For instance "joe@example.com".
+Name
+string
Optional name of party specified together with EMail .
+Contact
+string
Name and e-mail combined as "Name <E-Mail>". For instance "Joe Hudson
<joe@example.com>".
+Login
+string
The login name of an F2 user.
+PartyNo
+int
Party number as found in the F2 party registry.
+OrganizationNo
+int
Organization number of a party as found in the F2 party registry, optionally
specified together with PartyNo . Organization numbers are useful specify a
combination of party number and organization number when assigning for
instance a responsible user on a case.
+PickFirstMatch
+bool
+PickFirstMatch may optionally be used with PartyNo to uniquely specify a
Party resource. As party numbers can be used in multiple organizations, and it
+is optional to specify an organization number, PickFirstMatch can be used to
disambiguate. If PickFirstMatch is specified as false (default) it will cause an
error when the party specification is ambiguous, otherwise any (i.e. the "first")
applicable organization number is picked for the party.
+PartyType
+string
A PartyType may optionally be used together with an external party’s PartyNo to
attach a party type to the external party when creating a new case or matter, or
patching an existing case or matter. When PartyType is specified, the F2-REST
server will try to find a matching party type enumeration item by Code (external
id) or alternatively by Title in the F2 party type registry. If a matching party
type enumeration item is found it will be attached to the specified external party
on the case/matter. Note that an external party will be bound to a party type
exclusively in relation to the case/matter and not in the external party registry.
+PartyGroupReference data type
+A party group reference can be used to refer to a named group of parties — for instance a security
group, or just a single party (user, organization or other).
+38
+
+Table 10. PartyGroupReference properties
+Name
+Description
+Name
+string
Name of party group (as shown in the F2 desktop client).
+Id
+int
The group identifier (found in the database, not available in the F2 desktop
client).
+SynckronizationKey
+string
The synchronization key for the party.
+PartyNumber
+int
The party number of the party group. Can be used to referrer to any party
group, including security groups.
+ Core resources
= Cases
+Case resource
+This resource represents a single F2 case.
+Location
+Cases can be located directly by ID or case number using the URL templates found in the service
index. In addition to this there are lots of links to cases from other resources which makes it
possible to locare related cases simply by following the links.
+Lookup by case ID
+The link relation http://cbrain.com/casefile/rel/case-by-id identifies a URL template for
looking up cases by ID. The template uses the template parameter id for the case ID.
+A GET on the generated URL will return a redirect to the corresponding case resource.
+Example link from service document
+{
"http://cbrain.com/casefile/rel/case-by-id":
{
href: "https://.../{id}",
title: "Get case by ID"
}
}
+Lookup by case number
+The link relation http://cbrain.com/casefile/rel/case-by-case-number identifies a URL template
for looking up cases by case number. The template uses the template parameter caseNumber for
+39
+
+the case number.
+A GET on the generated URL will return a redirect to the corresponding case resource.
+Example link from service document
+{
"http://cbrain.com/casefile/rel/case-by-case-number":
{
href: "http://.../{caseNumber}",
title: "Get case by case number"
}
}
+40
+
+Properties
+41
+
+Table 11. Case properties
+Name
+Description
+Id
+int (read-only)
Internal identifier.
+CaseNumber
+string (read-only)
Official case number (for instance "2012 — 342").
+Title
+string (255 characters)
Case title.
+CreatedDate
+DateTime (read-only)
Date and time the case was created.
+ModifiedDate
+DateTime (read-only)
Date and time the case was last modified.
+Keyword
+Enumeration
First element of all keywords. This can either be in the format of
+##.##.## when used with keywords from "Kommunernes
+Landsforening" — or the complete path to a specific keyword name (as
seen from the desktop client).
+Keywords
+List of Enumeration named Keyword
The complete list of all keywords.
+JournalPlan
+Enumeration
Represents the Danish "Journalplan" used for "Kommunernes
Landsforening". When PATCHing the journal plan use the path
+/JournalPlan with a string value representing the journal plan code.
+The actual journal plan code is setup by the F2 administrator as the
value of "Ekstern ID" for journal plan entries.
+Responsible
+PartyItem
The party who is responsible for the case.
+InvolvedParties
+List of PartyItem named InvolvedParty
The involved parties of the case ("Sagens parter" in Danish — "case
parties").
+SupplementaryCaseWorkers
+List of PartyItem named SupplementaryCaseWorker
The supplementary case workers for the case.
+ProcessInstruction
+Enumeration
Represents the Danish "Handlingsfacet" used for "Kommunernes
Landsforening". When PATCHing the process instruction use the path
+/ProcessInstruction with a string value representing the process
+instruction code. The actual process instruction code is setup by the F2
administrator as the value of "Ekstern ID" for process instruction entries.
+42
+
+Table 11. Case properties
+Name
+Description
+Landsforening". When PATCHing the deletion action use the path
/DeletionAction with a string value representing the deletion action code. The
actual deletion action code is setup by the F2 administrator as the value of
"Ekstern ID" for deletion action entries.
+TaskGuideKey
+string
The task guide key identifying a task guide associated with the case. PATCHing
this value to null removes the task guide from the case.
+Link
+List of Link (read-only)
One or more links to other related resources.
+CprNumber
+string
An external identification number for a party related to the case. For example
in a Danish installation it could be the nationwide CVR number of a company or
the nationwide CPR number of a citizen.
+ExtensionData
+any XML
General purpose XML container for data related directly to the case. Can be set
via the create-extension-data link on the case resource.
+ExternalId
+string (255 characters)
ID representing some external ID. The actual use of this field is customer
specific. Can be set by PATCH only.
+PreviousCaseNumber
+string (256 characters)
Previous case number, usualy used to indicate what the case was called before
it was imported to F2.
+SecurityGroups
+List of PartyGroupItem named PartyGroup
The security groups, users or organizations that are part of the access
restrictions for the meeting. The parties are accessed by their name when
patching and creating cases.
+ExternalAccess
+Enumeration
Identifying how the case is accessible outside F2. Default codes are "Open",
"PartlyOpen" and "Closed" (configurable for the installation).
+Closed
+bool (read-only)
True if the case is closed. Otherwise the case is open. Depending on the F2
configuration certain changes on the case are not allowed when closed.
+43
+
+Table 11. Case properties
+Name
+Description
+Case deadline.
+The XML root element is <Case> .
+44
+
+Case example
+<Case xmlns="http://cbrain.com/casefile/schema/">
<Id>1046444</Id>
<CaseNumber>2022 - 60</CaseNumber>
<Title>Case 1</Title>
<CreatedDate>2022-02-03T15:31:26.293</CreatedDate>
<ModifiedDate>2022-02-03T15:34:40</ModifiedDate>
<Deadline>2022-02-10T15:34:40</Deadline>
<ModifiedBy>
<Name>James Wolt</Name>
<EMail>jw@cbrain.dk</EMail>
<Link href="..." rel="self" title="James Wolt" />
<Type>User</Type>
<Id>671771</Id>
<PartyNumber>37301</PartyNumber>
<CPRCVR>120390-2222</CPRCVR>
<CVR_P />
</ModifiedBy>
<CprNumber>62419361</CprNumber>
<ExternalId>AX-2468</ExternalId>
<Keyword>
<Title>Change request</Title>
<Path>Issuetyper/Change request</Path>
<Code>Emneord_Issuetyper_Change request</Code>
<Link href="http://localhost/f2/main/restservices/enum-types/KeyWord"
rel="http://cbrain.com/casefile/rel/enum-type" type="application/vnd.cbrain.casefile+xml"
title="Enumeration type" />
</Keyword>
<Keywords>
<Keyword>
<Title>Change request</Title>
<Path>Issuetyper/Change request</Path>
<Code>Emneord_Issuetyper_Change request</Code>
<Link href="http://localhost/f2/main/restservices/enum-types/KeyWord"
rel="http://cbrain.com/casefile/rel/enum-type" type="application/vnd.cbrain.casefile+xml"
title="Enumeration type" />
</Keyword>
</Keywords>
<Responsible>
<Name>James Wolt</Name>
<EMail>jw@cbrain.dk</EMail>
<Link href="..." rel="self" title="James Wolt" />
<Type>User</Type>
<Id>1006118</Id>
<PartyNumber>37301</PartyNumber>
<CPRCVR>120390-2222</CPRCVR>
<CVR_P />
</Responsible>
<Closed>false</Closed>
<Link href="..." rel="self" title="Case 1" />
<Link href="..." rel="down" title="Matters" />
<Link href="..." rel="http://cbrain.com/casefile/rel/create-matter" title="Add matter" />
<ExtensionData />
<SecurityGroups>
<PartyGroup>
<Name>James Wolt</Name>
<PartyNumber>37301</PartyNumber>
</PartyGroup>
<PartyGroup>
+45
+
+<PartyNumber>108</PartyNumber>
</PartyGroup>
</SecurityGroups>
<ExternalAccess>
<Title>Åben</Title>
<Path>Open</Path>
<Code>Open</Code>
<Abbreviation>Open</Abbreviation>
<Link href="..." rel="http://cbrain.com/casefile/rel/enum-type" title="Enumeration type"
/>
</ExternalAccess>
<ProgressCode>
<Title>ProgressCode 1</Title>
<Path>ProgressCode 1</Path>
<Code>ProgressCode 1</Code>
</ProgressCode>
<InvolvedParties>
<InvolvedParty>
<Name>Kirsten Svanholm-Nielsen</Name>
<EMail />
<Link href="..." rel="self" title="Kirsten Svanholm-Nielsen" />
<Type>External</Type>
<Id>1006125</Id>
<PartyNumber>39938</PartyNumber>
<SynchronizationKey />
<CPRCVR>070761-4218</CPRCVR>
</InvolvedParty>
</InvolvedParties>
<SupplementaryCaseWorkers>
<SupplementaryCaseWorker>
<Name>Grith Malm</Name>
<EMail>gm@cbrain.dk</EMail>
<Link href="..." rel="self" title="Grith Malm" />
<Type>User</Type>
<Id>1006124</Id>
<PartyNumber>874</PartyNumber>
<CPRCVR />
<CVR_P />
</SupplementaryCaseWorker>
</SupplementaryCaseWorkers>
</Case>
+Create new case
+A case may be created using the Post Once Exactly pattern (see Data manipulation). Follow the link
named http://cbrain.com/casefile/rel/create-case from the service index to locate the POE
resource for creating a case.
+46
+
+Table 12. Input parameters for creating a case
+Name
+Description
+Title
+string (required, max 255 characters)
The title of the new case.
+KeywordCode
+string
The code that represents a keyword to be associated with the new case.
This can either be in the format of ##.##.## when used with keywords
from "Kommunernes Landsforening" — or the complete path to a specific
keyword name (as seen from the desktop client) or the external ID of the
keyword. As the complete paths and external ID’s may overlap, the
external ID takes precedence.
+KeywordCodes
+List of string
A list of keyword codes. Each keyword code is handled in the same way as
the above singular KeywordCode .
+JournalPlanCode
+string
The code which represents the journal plan to be associated with the new
meeting. In Danish this is called "Journalplanskode" and is used only with
keywords from "Kommunernes Landsforening".
+DeletionActionCode
+string
The code that represents the deletion action to be associated with the new
meeting. In Danish this is called "Kassationskode" and is used only with
keywords from "Kommunernes Landsforening".
+ProcessInstructionCode
+string
The code that represents the process instruction to be associated with the
new case. In Danish this is called "Handlingsfacet" and is used only with
keywords from "Kommunernes Landsforening".
+TaskGuideKey
+string
The key that identifies a task guide to be associated with the new case.
+SecurityGroups
+List of PartyGroupReference
The list of security groups, users or organizations to include in the access
restrictions of the new case. The security groups are referenced by the
name shown in the F2 desktop client.
+ExternalAccessCode
+string
The enumeration code that represents the external acceess to be
associated with the new case.
+Responsible
+PartyReference
Specifies who is responsible for the new case.
+InvolvedParties
+List of PartyReference
Specifies the involved parties of the new case ("Sagens parter" in Danish -
-).
+47
+
+Table 12. Input parameters for creating a case
+Name
+Description
+Case deadline. .
+Example request for creating a case (include first POE step)
+POST /case-create-url HTTP/1.1
Content-Length: 0
+> HTTP/1.1 201 Created
> Location: /case-create-poc-url
> Content-Length: 0
+POST /case-create-poc-url HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 19
+Title=A+new+case
+Example request for creating a case with security groups "SG4" and "SG5" (excluding first POE step)
+POST /case-create-poc-url HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 93
+*** LINE BREAKS ADDED FOR READABILITY ***
Title=A+new+case+with+security+groups
&SecurityGroups%3a0.Name=SG4
&SecurityGroups%3a1.Name=SG5
+Modify case
+A case may be modified by issuing a PATCH request targeted at the case resource URL.
+The simple properties are straight forward to replace with similar typed values, but some of the
complex case properties need special encoding when patching. These properties are:
+48
+
+Table 13. Properties needing special encoding when patching
+Name
+Description
+Keyword
+Use a single string value refering to the Code value of the enumeration
item.
+Keywords
+Use an array of string values refering to the Code value of the
enumeration items.
+JournalPlan
+Use a single string value refering to the Code value of the enumeration
item.
+Responsible
+Use a PartyReference object to reference the requested party.
+InvolvedParties
+Use an array of PartyReference objects to reference the requested
parties.
+SupplementaryCaseWorkers
+Use an array of PartyReference objects to reference the requested
parties.
+ProcessInstruction
+Use a single string value refering to the Code value of the enumeration
item.
+DeletionAction
+Use a single string value refering to the Code value of the enumeration
item.
+ExtensionData
+Use a string to contain the XML.
+SecurityGroups
+Use an array of PartyGroupReference objects to reference the required
parties.
+ExternalAccess
+Use a single string value refering to the Code value of the enumeration
item.
+ProgressCode
+Enumeration
Use a single string value refering to the Code value of the enumeration
item. Can be either the external Id or the title of the progress code.
+Deadline
+DateTime
Case deadline.
+Navigation
+string
The item key of a task-guide task.
+49
+
+Example PATCH request with headers
+PATCH /case-url HTTP/1.1
Accept: application/vnd.cbrain.casefile+xml
Content-Type: application/json-patch
+[
{"value":"New case title", "op":"replace", "path":"/Title"},
{"value":"00.07.00", "op":"replace", "path":"/Keyword"},
{"value":"G10", "op":"replace", "path":"/ProcessInstruction"},
{"value":"B", "op":"replace", "path":"/DeletionAction"},
{"value":{"PartyNo":26}, "op":"replace", "path":"/Responsible"},
{"value":[{"PartyNo":26},{"PartyNo":28}], "op":"replace", "path":"/InvolvedParties"},
{"value":
[
{"Name":"SG4"},
{"Name":"SG5"}
],"op":"replace","path":"/SecurityGroups"}
]
+Delete case
+Deleting a case in F2 is not as easy as simply issuing a DELETE targeted at the case resource since
the delete operation requires a few parameters for input.
+A case is deleted by looking up the "delete case handler" linked to a case by the link relation
+http://cbrain.com/casefile/rel/delete-case . Follow this link and issue a POST to it with the
+following parameters:
+Table 14. Inputs for deleting a case
+Name
+Description
+DeleteReason
+string
A string which specifies why the case is deleted. This property is
required and is used for accountability purposes.
+GenerateReportForDeletedItems
+bool
A Boolean value specifying if a report-matter should be generated,
to document which documents what was deleted as a result of
deleting the case.
+Example request for deleting a case.
+POST /delete-case-url HTTP/1.1
Content-Type: application/x-www-form-urlencoded
+DeleteReason=Deleted+because+of+GDPR&GenerateReportForDeletedItems=true
+The response from deleting a case indicates if the deletion was successful for the case and
detailed information about matters that caused issues - like for instance in this example, where a
matter was journalized and in that way blocked deleting of it together with the case:
+50
+
+Example response from deleting a case
+<DeleteCaseResult>
<CaseDeleted>false</CaseDeleted>
<DeleteErrorMessage>A matter was not deleted</DeleteErrorMessage>
<ReportFailed>true</ReportFailed>
<ReportErrorMessage>Deadlock</ReportErrorMessage>
<MatterResults>
<MatterResult>
<Success>false</Success>
<Id>42</Id>
<MatterNumber>22</MatterNumber>
<Title>Some matter which was not deleted</Title>
<Creator>
<Name>Ulla Torkil</Name>
<EMail>ut@example.com</EMail>
<Link href="..." rel="self"/>
<Type>User</Type>
<Id>2156</Id>
<PartyNumber>20</PartyNumber>
<CPRCVR>12344321</CPRCVR>
<CVR_P>1234554321</CVR_P>
</Creator>
<Responsible>
<Name>Ulla Torkil</Name>
<EMail>ut@example.com</EMail>
<Link href="..." rel="self"/>
<Type>User</Type>
<Id>2156</Id>
<PartyNumber>20</PartyNumber>
<CPRCVR>12344321</CPRCVR>
<CVR_P>1234554321</CVR_P>
</Responsible>
<DeleteResult>Matter is journalized</DeleteResult>
<Link href="..." rel="self"/>
</MatterResult>
</MatterResults>
</DeleteCaseResult>
+51
+
+Table 15. Delete case response properties
+Name
+Description
+CaseDeleted
+bool
Indicates if the case was deleted or not.
+DeleteErrorMessage
+string
Optional error message.
+ReportFailed
+bool
Indicates if the delete operation failed to generate a new matter with a delete-
case report.
+ReportErrorMessage
+string
Optional error message for the delete-case report.
+MatterResults
+List of DeleteCaseMatterResult named MatterResult
See table below.
+Link
+List of Link
Links to related items. See below.
+Table 16. DeleteCaseMatterResult properties
+Name
+Description
+Success
+bool
Indicates if the matter was successfully deleted or not.
+Id
+int
Internal matter identifier.
+MatterNumber
+int (optional)
Displayed matter number.
+Title
+string
Matter title.
+Creator
+PartyItem
Matter creator.
+Responsible
+PartyItem
Matter responsible.
+DeleteResult
+string
Message describing the result of deleting the matter.
+The XML root element is <DeleteCaseResult> .
+The link list may contain a link to the generated case-delete report. The link is named
+http://cbrain.com/casefile/rel/case-delete-report .
+52
+
+Dry-run deleting a case
+If you only want to test what would happen when deleting a case, then there is also a "dry-run case
delete
+handler" —
+it
+is
+linked
+to
+a
+case
+by
+the
+link
+relation
+http://cbrain.com/casefile/rel/delete-case-dry-run . Follow this link and issue a POST to it
+with no parameters.
+If something fails in the dry-run it can be assumed that the same error will occur in the real
deletion, if performed by the same user. If, however, the user is allowed to bypass access
restrictions, then the dry-run result is purely advisory. In this case, the deletion may very well
succeed, depending on what the error was for a specific matter.
+Table 17. Dry-run delete case response properties
+Name
+Description
+PreviousReason
+string
If the case was attempted to be deleted previously but failed, then the
+DeleteReason provided to that call, is included here.
+MatterResults
+List of DeleteCaseMatterResult named MatterResult
Same content as when deleting a case.
+Close and open a case
+A case can be closed by issuing an empty POST request to the "Close case handler" linked to by
the link relation http://cbrain.com/casefile/rel/open-case from the case itself.
+In the same way, a case can be opened again by issuing an empty POST request to the "Open case
handler" linked to by the link relation http://cbrain.com/casefile/rel/open-case from the case
itself.
+Complete case structure including matters and documents
+Follow the link named http://cbrain.com/casefile/rel/structure to get a complete
representation of the case and its matters and their documents. See the section Complete case
structure.
+Matters
+All accessible matters related to a case can be found by following the link relation down from the
case. The response is a collection resource with links to all matters.
+53
+
+Table 18. Expected link relations
+Rel
+Description
+self
+Link to self.
+down
+Link to list of contained matters.
+alternate
+Link containing the URL for opening the case
in the desktop client.
+http://cbrain.com/casefile/rel/create-matter
+Link to POE factory for creating a matter
associated with the case. See Create matter.
+http://cbrain.com/casefile/rel/extension-data
+Link to related custom XML data.
+http://cbrain.com/casefile/rel/create-extension-
+Link for creating new related custom XML
+data
+data.
+http://cbrain.com/casefile/rel/notes
+Link to related notes. See Notes.
+http://cbrain.com/casefile/rel/create-note
+Link to POE factory for creating notes
associated with the case. See Add note.
+http://cbrain.com/casefile/rel/structure
+Link to complete case structure. See
pages/case-structure.html.
+http://cbrain.com/casefile/rel/related-cases
+Link to list of related cases.
+http://cbrain.com/casefile/rel/add-related-case
+Link to resource for adding related cases.
+http://cbrain.com/casefile/rel/field-data
+Link to related field data ("Sagens
oplysninger" in Danish).
+http://cbrain.com/casefile/rel/parties
+Link to all the parties related to the case. See
pages/party-collection.html.
+http://cbrain.com/casefile/rel/taskguidescripts-
+Link for executing task guide scripts.
+execute
+http://cbrain.com/casefile/rel/taskguidetasks-
+Link for completing a single task guide task.
+complete
+http://cbrain.com/casefile/rel/taskguidetasks-
+Link for executing a single task guide task.
+execute
+http://cbrain.com/casefile/rel/taskguide-state
+Link for getting the complete state of an
associated task guide (visibility of tasks as
well as field and variable values).
+http://cbrain.com/casefile/rel/open-case
+Link for opening the case. See Close and
open case.
+http://cbrain.com/casefile/rel/close-case
+Link for closing the case. See Close and open
case.
+54
+
+Table 18. Expected link relations
+Rel
+Description
+http://cbrain.com/casefile/rel/create-
+Link for creating a submission eventlog.
+submission-event-log
+http://cbrain.com/casefile/rel/delete-
+Link for dry-run deleting a case. See Dry run delete
+case-dry-run
+case.
+http://cbrain.com/casefile/rel/delete-
+Link for deleting a case. See Delete case.
+case
+http://cbrain.com/casefile/rel/update-
+Link which can be used to update one or more
+case-extension-data
+extension fields for the case. See Updating matter &
case extension fields.
+http://cbrain.com/casefile/rel/extension-
+Link to case extension record. See Case guide data.
+records
+55
+
+Complete case structure
Complete case structure resource
+This resource represents a subset of the meta data of a case and all its matters and documents as
one single resource.
+Location
+The
+case
+structure
+is
+reachable
+from
+a
+case
+via
+the
+link
+relation
+http://cbrain.com/casefile/rel/structure .
+Properties
Table 19. Case structure properties
+Name
+Description
+Id
+int
Internal identifier.
+CaseNumber
+string
Official case number (for instance "2012 - 342").
+Title
+string
Case title.
+CreatedDate
+DateTime
Date and time the case was created.
+ModifiedDate
+DateTime
Date and time the case was last modified.
+ModifiedBy
+PartyItem
Last user who modified the case.
+Responsible
+PartyItem
The party who is responsible for the case.
+Link
+List of Link (read-only)
One or more links to other related resources.
+Matters
+List of Matter
List of all accessible matters on the case.
+The XML root element is <Case> .
+56
+
+Example case structure
+<Case xmlns="http://cbrain.com/casefile/schema/">
<Id>517645</Id>
<CaseNumber>2016 - 22</CaseNumber>
<Title>Example case</Title>
<CreatedDate>2016-01-07T12:47:50.173</CreatedDate>
<ModifiedDate>2016-01-12T15:52:55</ModifiedDate>
<ModifiedBy>
<Name>Joe Noel</Name>
<EMail>jn@cbrain.dk</EMail>
<Link href="..."
rel="self"
title="Joe Noel" />
</ModifiedBy>
<Responsible>
<Name>Joe Noel</Name>
<EMail>jn@cbrain.dk</EMail>
<Link href="..."
rel="self"
title="Joe Noel" />
</Responsible>
<Matters>
<Matter>
<Id>517886</Id>
<MatterNumber>0</MatterNumber>
<Title>Example matter</Title>
<CreatedDate>2016-01-12T15:52:55</CreatedDate>
<ModifiedDate>2016-01-12T15:52:56</ModifiedDate>
<ModifiedBy>...</ModifiedBy>
<Responsible>...</Responsible>
<CaseNumber>2016 - 22</CaseNumber>
<Archived>false</Archived>
<Deadline xsi:nil="true" />
<Status>InProgress</Status>
<LetterDate xsi:nil="true" />
<ReceivedDate xsi:nil="true" />
<SentDate xsi:nil="true" />
<ReminderDate xsi:nil="true" />
<Documents />
<Link href="..."
rel="self"
title="Example matter" />
<Link href="..."
rel="http://cbrain.com/casefile/rel/structure"
title="Complete matter structure" />
</Matter>
<Matter>
<Id>517777</Id>
<MatterNumber>0</MatterNumber>
<Title>Example matter with documents</Title>
...
<Documents>
<Document>
<Id>517783</Id>
<Title>Example document</Title>
<ModifiedDate>2016-01-08T16:09:37.15</ModifiedDate>
<ModifiedBy>...</ModifiedBy>
<FileType>doc</FileType>
<ContentType>application/msword</ContentType>
+57
+
+<Link href="..."
rel="self"
title="Example document" />
</Document>
</Documents>
<Link ... />
</Matter>
<Matter>
<Id>517647</Id>
<MatterNumber>0</MatterNumber>
<Title>Last matter example</Title>
...
</Matter>
</Matters>
<Link href="..."
rel="self"
title="Example case" />
<Link href="..."
rel="http://cbrain.com/casefile/rel/structure"
title="Complete case structure" />
</Case>
+58
+
+Related cases
Related cases resource
+This resource represents a list of relations to other cases. Each relation contains a link to the
related case, a relation type and various links for manipulating the list.
+Cases can be related to each other as "Parent" or "Child" which are both each other’s inverse
relationship; if case A is parent to case B then case B is automatically child of A and vice versa. In
addition to this cases can be related to each other as "Duplicated" or simply "Related".
+Location
+The
+list
+of
+related
+cases
+is
+reachable
+from
+a
+case
+via
+the
+link
+relation
+http://cbrain.com/casefile/rel/related-cases .
+59
+
+Properties
Table 20. Case relation properties
+Name
+Description
+CaseId
+int
Source case ID.
+CaseNumber
+string
Source case number.
+CaseTitle
+string
Source case title.
+Relation
+Relation
Zero or more relations to other cases.
+Relation.CaseId
+int
Related case ID.
+Relation.CaseNumber
+string
Related case number.
+Relation.CaseTitle
+string
Related case title.
+Relation.RelationType
+string
Type of relation between the two cases. Possible values are:
+Parent : Source case is parent of the related case.
+Child : Source case is child of the related case.
+Duplicated : Source case is a duplicate of the related case.
+Related : Source case has no specific relationship to the related
+case.
+Relation.Link
+List of Link
One or more links to other related resources.
+``
+x
.
+Link
+List of Link
One or more links to other related resources.
+The root XML element is Relations .
+60
+
+Related cases example
+<Relations xmlns="http://cbrain.com/casefile/schema/">
<CaseId>5899664</CaseId>
<CaseNumber>2016 - 74362</CaseNumber>
<CaseTitle>Test case</CaseTitle>
<Relation>
<CaseId>5899676</CaseId>
<CaseNumber>2016 - 74365</CaseNumber>
<CaseTitle>Related case 1</CaseTitle>
<RelationType>Parent</RelationType>
<Link href="..." rel="http://cbrain.com/casefile/rel/related-case" />
<Link href="..." rel="http://cbrain.com/casefile/rel/delete-related-case" />
</Relation>
<Relation>
<CaseId>5899678</CaseId>
<CaseNumber>2016 - 74366</CaseNumber>
<CaseTitle>Related case 2</CaseTitle>
<RelationType>Child</RelationType>
<Link href="..." rel="http://cbrain.com/casefile/rel/related-case" />
<Link href="..." rel="http://cbrain.com/casefile/rel/delete-related-case" />
</Relation>
<Link href="..." rel="self" />
<Link href="..." rel="up" />
</Relations>
+Table 21. Expected link relations
+Rel
+Description
+self
+Link to the list of related cases.
+up
+Link to parent case.
+Table 22. Expected link relations for related cases
+Rel
+Description
+http://cbrain.com/casefile/rel/related-
+Link to related case.
+case
+http://cbrain.com/casefile/rel/delete-
+Link to resource for deleting the containing case
+related-case
+relation
+Add new relation
+Follow the link named http://cbrain.com/casefile/rel/add-related-case from a case to find a
resource for adding new case relations. Then issue an POST to that resource with the input
parameters listed below.
+61
+
+Table 23. Input parameters for adding a related case relation
+Name
+Description
+CaseId
+int
Identifier of related case.
+RelationType
+string
Case relation type. Possible values are:
+Parent
+Child
+Duplicated
+Related
+Special HTTP status codes from adding a new case relation:
+201 Created
+Relation did not exist already and was created.
+200 OK
+Relation existed already and no new relation was created.
+Add related case example request
+POST add-related-case-url HTTP/1.1
Accept: application/vnd.cbrain.casefile+xml
Content-Type: application/x-www-form-urlencoded
+CaseId=279641&RelationType=Parent
+Delete case relation
+Follow the link named http://cbrain.com/casefile/rel/delete-related-case in the link
collection of a single relation, to find a resource for deleting the relation. Then issue an empty
+POST request to that resource in order to delete the relation.
+A DELETE operation would seem more appropriate for this purpose, but it does not allow later
versions of F2-REST to include parameters in the request if needed.
+Delete related case example
+POST related-case-delete-url HTTP/1.1
Accept: application/vnd.cbrain.casefile+xml
Content-Length: 0
+62
+
+Matters
Matter resource
+This resource represents a single F2 matter.
+Location
+Matters can be located directly by ID or matter number using the URL templates found in the
service index. In addition to this there are links from a case to all the matters on the case.
+Lookup by matter ID
+The link relation http://cbrain.com/casefile/rel/matter-by-id identifies a URL template for
looking up matters by ID. The template uses the template parameter id for the matter ID.
+A GET on the generated URL will return a redirect to the corresponding matter resource.
+Example link from service document
+{
"http://cbrain.com/casefile/rel/matter-by-id":
{
href: "http://.../{id}",
title: "Get matter by ID"
}
}
+Lookup by matter number
+The link relation http://cbrain.com/casefile/rel/matter-by-matter-number identifies a URL
template for looking up matters by matter number. The template uses the template parameter
+matterNumber for the matter number.
+A GET on the generated URL will return a redirect to the corresponding matter resource.
+Example link from service document
+{
"http://cbrain.com/casefile/rel/matter-by-matter-number":
{
href: "http://.../{matterNumber}",
title: "Get matter by matter number"
}
}
+63
+
+Properties
+64
+
+Table 24. Matter properties
+Name
+Description
+Id
+int (read-only)
Internal matter identifier.
+MatterNumber
+int (read-only)
Unique public matter number.
+CaseMatterNumber
+int (optional, read-only)
Matter number relative to the matter’s associated case.
+VersionNumber
+int (read-only)
Matter version number.
+IsActiveVersion
+bool (read-only)
Flag which indicates if this is the active version of the matter.
+Title
+string (255 characters)
Matter title.
+CreatedDate
+DateTime (read-only)
Date and time the matter was created.
+ModifiedDate
+DateTime (read-only)
Date and time the matter was last modified.
+BinnedDate
+DateTime (read-only)
Date and time the matter was binned (deleted).
+CaseNumber
+string (read-only)
Number of the case related to the matter. The actual case representation can be
found by following the link relation "up".
+Text
+string
Text body of the matter — also called "dossier document" in the desktop client. If
the matter does not have a dossier document then Text will be null. A patch
request, patching the Text property, will return status 400 , if the matter does
not have a dossier document (which may happen for approval matters).
+Type
+string
Type of matter. The possible values are:
+Internal — represents a matter that exists only in F2.
+Inbound — represents a matter that has been received via an external
+channel.
+Outbound — represents a matter that has been sent out of F2.
+AccessLevel
+string
Access level. The possible values are Involved , Unit and All .
+65
+
+Table 24. Matter properties
+Name
+Description
+Deadline
+DateTime
Optional deadline for the matter.
+Archived
+bool (read-only)
Archival status of the matter.
+CprNumber
+x (12 characters)
An external identification number for a party in case a specific party is
related to the matter. For example, in a Danish installation it could be
the national CVR number of a company or the national CPR number of a
citizen.
+Status
+string (read-only)
Matter status. Possible values are InProgress and Closed .
+PreviousCaseNumber
+string (255 characters)
Previous case number.
+LetterDate
+DateTime
Letter date — a general purpose date field. If LetterDate is set explicitly
then the assigned value will be returned as LetterDate too. If
+LetterDate is not set, then either ReceivedDate or SentDate will be
+returned as LetterDate (only one of ReceivedDate or SentDate should
ever be set).
+ReceivedDate
+DateTime
Received date. This property is ignored when creating outgoing matters.
+SentDate
+DateTime
Sent date.
+Responsible
+PartyItem
The party who is responsible for the matter.
+Sender
+PartyItem
The sender of the matter.
+Receivers
+List of PartyItem named Receiver
The receivers of the matter.
+CcReceivers
+List of PartyItem named CcReceiver
The CC receivers of the matter.
+BccReceivers
+List of PartyItem named BccReceiver
The BCC receivers of the matter.
+InvolvedParties
+List of PartyItem named InvolvedParty
The involved parties of the matter ("Aktparter" in Danish).
+66
+
+Table 24. Matter properties
+Name
+Description
+This is a temporary value used only when modifying a matter. See Modify matter.
+Alerts
+List of Alert named Alert
List of alerts related to this dossier (see below).
+SecurityGroups
+List of PartyGroupItem named PartyGroup
The security groups, users or organizations that are part of the access
restrictions for the meeting. The parties are accessed by their name when
patching and creating matters.
+Link
+List of Link (read-only)
One or more links to other related resources.
+ExtensionData
+Any XML
General purpose XML container for data related directly to the matter. Can be
set via the create-extension-data link on the matter resource.
+ExternalAccess
+Enumeration
Identifying how the matter is accessible outside F2. Default values are Open ,
+PartlyOpen and Closed (the complete list if configurable for the installation).
+DeliveryType
+string
Identifies the method for sending the matter out of F2 once it is created.
Possible values are:
+None — do not send.
+EMail — send via e-mail.
+OutputManager — send via the Danish "Fjernprint".
+DigitalMail — send via the Danish "E-Boks".
+BOM — send via the Danish "Byg og Miljø".
+ExternalRequisition — send as external requisition.
+DistributedRequisitionAnswer — send as answer to distributed
+requisition.
+DistributedRequisition — send as distributed requisition.
+M4Mail — send via M4.
+DigitalMailV3 — send via the Danish "Digitalpost", version 3.
+Beware that it is only possible to create new matters or patch existing
matters with the delivery types None , EMail , M4Mail , DigitalMail and
+OutputManager . The rest of the delivery types are managed internally by F2
+and are only readable in GET requests
+67
+
+Table 24. Matter properties
+Name
+Description
+The item key of a task-guide task.
+Table 25. Alert properties
+Name
+Description
+Type
+string
The type of the alert. The list of types is not fixed. Use the value "Other" for
unexpected errors.
+Description
+string
Detailed description of the alert. It may be shown to the user in the F2 client,
possibly together with a general description of the alert type.
+User
+PartyItem
The user for which the alert should be visible.
+The XML root element is <Matter> .
+68
+
+Matter example
+<Matter xmlns="http://cbrain.com/casefile/schema/">
<Id>1046445</Id>
<MatterNumber>106844</MatterNumber>
<CaseMatterNumber>1</CaseMatterNumber>
<VersionNumber>1</VersionNumber>
<Title>Matter 1</Title>
<CreatedDate>2022-02-03T15:31:28</CreatedDate>
<ModifiedDate>2022-02-07T11:04:23</ModifiedDate>
<ModifiedBy>
<Name>James Wolt</Name>
<EMail>jw@cbrain.dk</EMail>
<Link href="..." rel="self" title="James Wolt" />
<Type>User</Type>
<Id>671771</Id>
<PartyNumber>37301</PartyNumber>
<CPRCVR>120390-2222</CPRCVR>
<CVR_P />
</ModifiedBy>
<CaseNumber>2022 - 60</CaseNumber>
<Text>...</Text>
<CprNumber>12345678</CprNumber>
<Type>Internal</Type>
<AccessLevel>All</AccessLevel>
<Deadline>2022-03-04T00:00:00</Deadline>
<Archived>true</Archived>
<Status>InProgress</Status>
<PreviousCaseNumber>Example-2910-YE23</PreviousCaseNumber>
<LetterDate>2022-02-07T00:00:00</LetterDate>
<ReceivedDate>2022-02-07T00:00:00</ReceivedDate>
<SentDate>2022-02-07T00:00:00</SentDate>
<ReminderDate>2022-02-17T00:00:00</ReminderDate>
<Sender>
<Name>James Wolt</Name>
<EMail>jw@cbrain.dk</EMail>
<Link href="..." rel="self" title="James Wolt" />
<Type>User</Type>
<Id>1006121</Id>
<PartyNumber>37301</PartyNumber>
<CPRCVR>120390-2222</CPRCVR>
<CVR_P />
</Sender>
<Receivers>
<Receiver>
<Name>Gunnar Holgersen</Name>
<EMail />
<Link href="..." rel="self" title="Gunnar Holgersen" />
<Type>External</Type>
<Id>1006145</Id>
<PartyNumber>39942</PartyNumber>
<SynchronizationKey />
<CPRCVR>090441-1234</CPRCVR>
</Receiver>
</Receivers>
<CcReceivers />
<BccReceivers />
<InvolvedParties>
<InvolvedParty>
<Name>Allerslev I/S</Name>
+69
+
+<Link href="..." rel="self" title="Allerslev I/S" />
<Type>External</Type>
<Id>1006147</Id>
<PartyNumber>81716</PartyNumber>
<SynchronizationKey>CVR_14147683</SynchronizationKey>
<CPRCVR>14147683</CPRCVR>
</InvolvedParty>
</InvolvedParties>
<Responsible>
<Name>James Wolt</Name>
<EMail>jw@cbrain.dk</EMail>
<Link href="..." rel="self" title="James Wolt" />
<Type>User</Type>
<Id>1006122</Id>
<PartyNumber>37301</PartyNumber>
<CPRCVR>120390-2222</CPRCVR>
<CVR_P />
</Responsible>
<SupplementaryCaseWorkers>
<SupplementaryCaseWorker>
<Name>Sue Cheriff</Name>
<EMail />
<Link href="..." rel="self" title="Sue Cheriff" />
<Type>User</Type>
<Id>1006146</Id>
<PartyNumber>108</PartyNumber>
<CPRCVR />
<CVR_P />
<Access>Read</Access>
</SupplementaryCaseWorker>
</SupplementaryCaseWorkers>
<SkipInboxForCaseWorkers>false</SkipInboxForCaseWorkers>
<Link href="..." rel="self" title="Matter 1" />
<Link href="..." rel="http://cbrain.com/casefile/rel/pdf-content" title="PDF content" />
<Link href="..." rel="http://cbrain.com/casefile/rel/create-document" title="Add document"
/>
<ExtensionData />
<SecurityGroups>
<PartyGroup>
<Name>James Wolt</Name>
<PartyNumber>37301</PartyNumber>
</PartyGroup>
<PartyGroup>
<Name>Sue Cheriff</Name>
<PartyNumber>108</PartyNumber>
</PartyGroup>
</SecurityGroups>
<Alerts>
<Alert>
<Type>SendMail</Type>
<Description>The dossier cannot be sent because it belongs to a closed case.
</Description>
<User>
<Name>James Wolt</Name>
<EMail>jw@cbrain.dk</EMail>
<Link href="..." rel="self" title="James Wolt" />
<Type>User</Type>
<Id>671771</Id>
<PartyNumber>37301</PartyNumber>
<CPRCVR>120390-2222</CPRCVR>
+70
+
+</User>
</Alert>
</Alerts>
<ExternalAccess>
<Title>Åben</Title>
<Path>Open</Path>
<Code>Open</Code>
<Abbreviation>Open</Abbreviation>
<Link href="..." rel="http://cbrain.com/casefile/rel/enum-type" title="Enumeration type"
/>
</ExternalAccess>
<DeliveryType>EMail</DeliveryType>
<Keywords>
<Keyword>
<Title>Emneord A</Title>
<Path>Område A/Emneord A</Path>
<Code>Emneord_Område A_Emneord A</Code>
<Abbreviation />
<Link href="..." rel="http://cbrain.com/casefile/rel/enum-type" title="Enumeration type"
/>
</Keyword>
</Keywords>
<Versions>
<MatterVersion>
<VersionNumber>2</VersionNumber>
<IsActiveVersion>true</IsActiveVersion>
<Link href="..." rel="self" />
</MatterVersion>
<MatterVersion>
<VersionNumber>1</VersionNumber>
<IsActiveVersion>false</IsActiveVersion>
<Link href="..." rel="self" />
</MatterVersion>
</Versions>
</Matter>
+71
+
+Table 26. Expected link relations
+Rel
+Description
+self
+Link to self
+down
+Link to list of contained documents.
+up
+Link to parent case file.
+alternate
+Link containing the URL for opening the matter in
the desktop client.
+http://cbrain.com/casefile/rel/pdf-
+Link to PDF representation of the matter text.
+content
+http://cbrain.com/casefile/rel/create-
+Link to POE factory for creating documents
+document
+associated with the matter. See Create document.
+http://cbrain.com/casefile/rel/upload-
+Link to upload validation for validation before
+validation
+creating a document. See Upload validation.
+http://cbrain.com/casefile/rel/extension-
data
+http://cbrain.com/casefile/rel/create-
extension-data
+http://cbrain.com/casefile/rel/notes
+Link to list of related notes. See Notes.
+http://cbrain.com/casefile/rel/create-
+Link to POE factory for creating notes associated
+note
+with the matter. See Add note.
+http://cbrain.com/casefile/rel/chats
+Link to list of related chats. See Chats.
+http://cbrain.com/casefile/rel/create-
+Link to POE factory for creating chats associated
+chat
+with the matter. See Add chat.
+http://cbrain.com/casefile/rel/structure
+Link
+to
+complete
+matter
+structure.
+See
+pages/matter-structure.html.
+72
+
+Table 26. Expected link relations
+Rel
+Description
+exclude_meta: Exclude matter meta data
+exclude_matter_doc Exclude matter document
+exclude_approval_meta:
+Exclude
+approval
+meta data
+include_approval_doc
+Include
+approval
+document
+exclude_attachments: Exclude attachments
+exclude_meta: Exclude matter meta data
+exclude_matter_doc Exclude matter document
+exclude_approval_meta:
+Exclude
+approval
+meta data
+include_approval_doc
+Include
+approval
+document
+exclude_attachments: Exclude attachments
+http://cbrain.com/casefile/rel/approval
+Link to approval process associated with matter. The
link will only show up if an approval process is
associated with the matter.
+http://cbrain.com/casefile/rel/create-
+Link to POE factory for creating an approval process
+approval
+associated with the matter. The link will only show
up if no approval processes are associated with the
matter.
+http://cbrain.com/casefile/rel/set-case
+Link which can be used to attach the matter to a
case. See Attach matter to case.
+http://cbrain.com/casefile/rel/update-
+Link which can be used to update one or more
+matter-extension-data
+extension fields for the matter. See Updating matter
& case extension fields.
+http://cbrain.com/casefile/rel/set-
+Link which can be used to set or change the
+responsible
+responsible party. See Set responsible party for
matter.
+http://cbrain.com/casefile/rel/active-
+Link which can be used to get the active version of
+version
+the current matter.
+73
+
+Table 26. Expected link relations
+Rel
+Description
+http://cbrain.com/casefile/rel/mark-
+Link which can be used to mark a matter as having
+as-physical-mail
+been sent via physical mail. This is done by issuing a
+POST to the link. Note that the operation is not POE
+protected, as it is idempotent. It should however be
noted, that performing the operation twice on the same
matter, will result in a 400 . Check that the matter is
marked as being sent, in order to verify that the
operation has succeeded.
+Create new matter
+A matter may be created using the Post Once Exactly pattern (see Data manipulation). Follow the
link named http://cbrain.com/casefile/rel/create-matter from the service index to locate the
POE resource for creating a matter — or follow the same link from a specific case in order to
associate the created matter with that case.
+74
+
+Table 27. Input parameters for creating a matter
+Name
+Description
+Title
+string (required, 255 characters)
The title of the new matter.
+Type
+string (required)
The type of matter to create. The list of possible values is the same as those
for the property Type on a Matter resource.
+Text
+string
The textual body (also called "dossier document"). The text should be
represented as HTML.
+CprNumber
+string (12 characters)
An external identification number for a party related to the matter. For
example, in a Danish installation it could be the national CVR number of a
company or the national CPR number of a citizen.
+AccessLevel
+string
Specifies access level. The list of possible values is the same as that for the
property AccessLevel on a Matter resource.
+Deadline
+DateTime
Specifies deadline for the new matter.
+Archived
+bool
Specifies whether or not the new matter is archived.
+Status
+string
Specifies status. The list of possible values is the same as that for the property
+Status on a Matter resource.
+Responsible
+PartyReference
Specifies who is responsible for the new matter.
+Sender
+PartyReference
Specifies the sender of the new matter.
+Receivers
+List of PartyReference
Specifiers the receivers of the new matter.
+CcReceivers
+List of PartyReference
Specifiers the CC receivers of the new matter.
+BccReceivers
+List of PartyReference
Specifiers the BCC receivers of the new matter.
+InvolvedParties
+List of PartyReference
Specifies the involved parties of the new matter ("Aktparter" in Danish).
+ExternalAccessCode
+string
The enumeration code that represents the external acceess to be associated
+75
+
+Table 27. Input parameters for creating a matter
+Name
+Description
+with the new matter.
+LetterDate
+DateTime
Specifies letter date.
+ReceivedDate
+DateTime
Specifies when the matter was received. The value is ignored when creating
output matters.
+SentDate
+DateTime
Specifies when the matter was sent.
+ReminderDate
+DateTime
Specifies reminder date ("Erindringsdato" in Danish).
+PreviousCaseNumber
+string (255 characters)
Specifies previous case number (can be any string — not necessarily a F2 case
number).
+SecurityGroups
+List of PartyGroupReference
The list of security groups, users or organizations to include in the access
restrictions of the new case. The security groups are referenced by the name
shown in the F2 desktop client.
+DeliveryType
+string
+Possible values are:
+None — do not send.
+EMail — send via e-mail.
+OutputManager — send via the Danish "Fjernprint".
+DigitalMail — send via the Danish "E-Boks".
+M4Mail — send via M4.
+DigitalMailV3 — send via the Danish "Digitalpost", version 3.
+KeywordCodes
+List of string
A list of keyword codes to be associated with the new matter. This can either
be in the format of ##.##.## when used with keywords from "Kommunernes
Landsforening" — or the complete path to a specific keyword name (as seen
from the desktop client) or the external id of the keyword. As the complete
path and external id may overlap, the external id takes precedence.
+There is no need to supply any reference to the parent case since that is embedded in the URL of
the factory resource.
+Input values are encoded according to the rules in Input encoding.
+76
+
+Example 1 (simple URL encoded parameters including initial POE step)
+POST /matter-create-url HTTP/1.1
Content-Length: 0
+> HTTP/1.1 201 Created
> Location: /matter-create-poc-url
> Content-Length: 0
+POST /matter-create-poc-url HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 50
+Type=Internal&Title=A+new+matter&Archived=false
+Example 2 (complex URL encoded parameters)
+POST /matter-create-poc-url HTTP/1.1
Accept: application/vnd.cbrain.casefile+xml
Content-Type: application/x-www-form-urlencoded
Authorization: Bearer tgkVLxr3J7x2BZzUoKPB
Content-Length: 288
+*** LINE BREAKS ADDED FOR READABILITY ***
Type=Outbound
&Title=En+ny+akt&Text=Denne+akt+er+oprettet+som+REST+demo.
&Archived=false
&Sender.Name=Peter+Nielsen
&Sender.EMail=pn%40example.com
&Receivers%3a0.Name=cBrain+DK
&Receivers%3a0.EMail=dk%40cbrain.dk
&Receivers%3a1.Name=cBrain+US
&Receivers%3a1.EMail=info%40cbrain.com
+Example 3 (complex JSON encoded parameters, same values as above)
+POST /matter-create-poc-url HTTP/1.1
Accept: application/vnd.cbrain.casefile+xml
Content-Type: application/json
Authorization: Bearer D6pV2jNchtZOTwFYtyAU
Content-Length: 588
+{
"Type":"Internal",
"Title":"En ny akt",
"Text":"Denne akt er oprettet som REST demo.",
"Archived":false,
"Sender": { "Name":"Peter Nielsen", "EMail":"pn@example.com" },
"Receivers": [
{ "Name":"cBrain DK", "EMail":"dk@cbrain.dk },
{ "Name":"cBrain US", "EMail":"info@cbrain.com" }
]
}
+Modify matter
+77
+
+The simple properties are straight forward to replace with similar typed values, but some of the
complex matter properties need special encoding when patching. These properties are:
+Table 28. Properties needing special encoding when patching
+Name
+Description
+Sender
+Use a PartyReference object to reference the requested party.
+Receivers
+Use an array of PartyReference objects to reference the requested
parties.
+CcReceivers
+Use an array of PartyReference objects to reference the requested
parties.
+BccReceivers
+Use an array of PartyReference objects to reference the requested
parties.
+InvolvedParties
+Use an array of PartyReference objects to reference the requested
parties.
+SupplementaryCaseWorkers
+Use an array of PartyReference objects to reference the requested
parties.
+SkipInboxForCaseWorkers
+Set SkipInboxForCaseWorkers to true to avoid the matter being moved
to the inbox for the supplementary case workers when patching such in
+SupplementaryCaseWorkers .
+Keywords
+Use an array of string values refering to the Code value of the
enumeration items.
+Responsible
+Use a PartyReference object to reference the requested party.
+SecurityGroups
+Use an array of PartyGroupReference objects to reference the required
parties.
+ExternalAccess
+Use a single string value refering to the Code value of the enumeration
item.
+Alerts
+Use an array of complete Alert objects (see Alert above) — but use a
+PartyReference object for the User part.
+78
+
+Example PATCH request with headers
+PATCH /matter-url HTTP/1.1
Accept: application/vnd.cbrain.casefile+xml
Content-Type: application/json-patch
+[
{"value":"Outbound","op":"replace","path":"/Type"},
{"value":"Changed title","op":"replace","path":"/Title"},
{"value":"Changed text","op":"replace","path":"/Text"},
{"value":"Closed","op":"replace","path":"/Status"},
{"value":"2013-05-14T08:15:29.436Z","op":"replace","path":"/Deadline"},
{"value":"010100-1234","op":"replace","path":"/CprNumber"},
{"value":"All","op":"replace","path":"/AccessLevel"},
{"value":true,"op":"replace","path":"/Archived"},
{"value":{"PartyNo":26},"op":"replace","path":"/Responsible"},
{"value":[{"PartyNo":26},{"PartyNo":28}],"op":"replace","path":"/InvolvedParties"},
{"value":{"Contact":"Knud Nielsen <kn@cbrain.dk>"},"op":"replace","path":"/Sender"},
{"value":
[
{"Contact":"John <john@cbrain.dk>"},
{"Contact":"J\u00FCrgen \u00C6sel\u00F8re <jaeoe@cbrain.com>"}
],"op":"replace","path":"/Receivers"},
{"value":
[
{"Contact":"Carsten <carsten@cbrain.dk>"}
],"op":"replace","path":"/CcReceivers"},
{"value":
[
{"Contact":"Pia <pia@cbrain.dk>"}
],"op":"replace","path":"/BccReceivers"},
{"value":
[
{"Name":"SG4"},
{"Name":"SG5"}
],"op":"replace","path":"/SecurityGroups"}
]
+Attach matter to case
+Attaching a matter to a case is done by sending a POST to the link with rel type
+http://cbrain.com/casefile/rel/set-case , found on the matter resource, rather than through a
+matter PATCH . Attaching a matter to a case can change the access restrictions of the matter.
+79
+
+Table 29. Input parameters for attaching a matter to a case
+Name
+Description
+CaseNumber
+string (required)
The case number of the case, which the matter should be attached
to.
+InheritNewCaseSecurityGroups
+bool
Specifies whether or not the matter should inherit the access
restriction from the new case. If the matter does not have any
security groups itself the value of this parameter is ignored and the
value is set to true.
If this parameter is not specified the value will default to true.
+Delete matter for current user only
+A matter may be deleted for the current user only, simply by issuing an DELETE request at the
matter resource.
+Delete matter for everybody
+A matter can be deleted completely for everybody, by looking up the "delete matter handler"
linked to a matter by the link relation http://cbrain.com/casefile/rel/matter-delete-everyone .
Follow this link and issue an empty POST to it in order order to delete the matter.
+Multiple identical POST requests are allowed (with no additional effect) as deleting a matter
multiple times will not have any additional effect.
+Delete matter via cleaning list
+A matter can be deleted for everybody as if done via a cleaning list. This is somewhat similar to
Delete matter for everybody. The main difference being that this resource requires privileges
related cleaning lists, in order to be used. If a user has the correct privilege, this resource allows for
more aggressive deletion, such as overruling case semantics.
+In order to use this resource find the link on the Matter resource, with rel type
+http://cbrain.com/casefile/rel/matter-delete-cleaing-list . Follow the link and issue a POST .
+Table 30. Inputs for deleting a matter
+Name
+Description
+DeleteReason
+string
A string which specifies why the matter is deleted. This property is
required and is used for accountability purposes.
+GenerateReportForDeletedItems
+bool
A Boolean value specifying if a report-matter should be generated,
to document which documents what was deleted as a result of
deleting the matter.
+80
+
+Example request for deleting a matter.
+POST /delete-case-url HTTP/1.1
Content-Type: application/x-www-form-urlencoded
+DeleteReason=Deleted+because+of+GDPR&GenerateReportForDeletedItems=true
+The response from deleting a matter indicates if the deletion successful.
+Example response from deleting a matter
+<DeleteMatterResult>
<MatterDeleted>false</MatterDeleted>
<DeleteErrorMessage>A matter was not deleted</DeleteErrorMessage>
<ReportFailed>true</ReportFailed>
<ReportErrorMessage>Deadlock</ReportErrorMessage>
</DeleteMatterResult>
+Table 31. Delete matter response properties
+Name
+Description
+MatterDeleted
+bool
Indicates if the matter was deleted or not.
+DeleteErrorMessage
+string
Optional error message.
+ReportFailed
+bool
Indicates if the delete operation failed to generate a new matter with a delete-
case report.
+ReportErrorMessage
+string
Optional error message for the delete-case report.
+Link
+List of Link
Links to related items. See below.
+The XML root element is <DeleteMatterResult> .
+The link list may contain a link to the generated matter-delete report. The link is named
+http://cbrain.com/casefile/rel/matter-delete-report .
+Documents
+All documents related to a matter can be found by following the link relation down from the matter.
The response is a collection resource with links to all documents.
+Set responsible party for matter
+Setting responsible party can be done by sending a POST to the link with rel type
+http://cbrain.com/casefile/rel/set-responsible , found on the matter resource. This can also
+be done through a matter PATCH , but this link only updates the responsible party. It can therefore
+81
+
+be used in cases where the user performing the request does not have write access to the matter,
but has been given the ReassignAllDossiers privilege.
+Table 32. Input parameters for setting responsible party
+Name
+Description
+Responsible
+PartyItem
The party who is responsible for the matter.
+Matter version
+Represents a pointer to a specific version of a matter. Each version points to a full matter.
+Table 33. MatterVersion properties
+Name
+Description
+VersionNumber
+int (read-only)
Matter version number.
+IsActiveVersion
+bool (read-only)
Flag which indicates if this is the active version of
the matter.
+Table 34. Expected link relations
+Rel
+Description
+self
+Link to the full matter this version represents.
+82
+
+Complete matter structure
Complete matter structure resource
+This resource represents a subset of the meta data of a matter and all its documents as one single
resource.
+Location
+The
+matter
+structure
+is
+reachable
+from
+a
+matter
+via
+the
+link
+relation
+http://cbrain.com/casefile/rel/structure.
+83
+
+Properties
+84
+
+Table 35. Matter structure properties
+Name
+Description
+Id
+int
Internal identifier.
+MatterNumber
+int
Unique public matter number.
+CaseMatterNumber
+int (optional)
Matter number relative to it’s associated case.
+Title
+string
Matter title.
+CreatedDate
+DateTime
Date and time the matter was created.
+ModifiedDate
+DateTime
Date and time the matter was last modified.
+ModifiedBy
+PartyItem
Last user who modified the matter.
+BinnedDate
+DateTime (read-only)
Date and time the matter was binned (deleted).
+CaseNumber
+string
Number of the case related to the matter. The actual case representation can be
found by following the link relation up .
+Deadline
+DateTime
Optional deadline for the matter.
+Archived
+bool
Archival status of the matter.
+CprNumber
+string
An external identification number for a party in case a specific party is related to
the matter.
+LetterDate
+DateTime
Letter date ("brevdato" in Danish) — a general purpose date field. If LetterDate
is set explicitly then the assigned value will be returned as LetterDate too. If
+LetterDate is not set then either ReceivedDate or SentDate will be returned as
LetterDate (only one of ReceivedDate or SentDate should ever be set).
+ReceivedDate
+DateTime
Received date.
+SentDate
+DateTime
Sent date.
+85
+
+Table 35. Matter structure properties
+Name
+Description
+Responsible
+PartyItem
The party who is responsible for the matter.
+Link
+List of Link (read-only)
One or more links to other related resources.
+Documents
+List of Document
List of all documents on the matter. Each element in the list represents a
subset of the meta data of a document.
+Document.Id
+int
Internal identifier.
+Document.Title
+string
Document title.
+Document.ModifiedDate
+DateTime
Date and time the document was last modified.
+Document.ModifiedBy
+PartyItem
Last user who modified the document.
+Document.FileType
+string
Document file type (file name extension as for instance "pdf" or "doc").
+Document.ContentType
+string
Document mime type (for instance "application/pdf").
+Document.FileSize
+int
Size of document (number of bytes).
+Document.Link
+Link
One or more links to other related resources.
+The XML root element is <Matter> .
+86
+
+Matter structure example
+<Matter xmlns="http://cbrain.com/casefile/schema/">
<Id>517777</Id>
<MatterNumber>0</MatterNumber>
<Title>Example matter</Title>
<CreatedDate>2016-01-08T15:56:48</CreatedDate>
<ModifiedDate>2016-01-08T16:09:42</ModifiedDate>
<ModifiedBy>
<Name>Joe Noel</Name>
<EMail>jn@cbrain.dk</EMail>
<Link href="..."
rel="self"
title="Joe Noel" />
</ModifiedBy>
<Responsible>...</Responsible>
<CaseNumber>2016 - 22</CaseNumber>
<Archived>false</Archived>
<Deadline xsi:nil="true" />
<Status>InProgress</Status>
<LetterDate xsi:nil="true" />
<ReceivedDate xsi:nil="true" />
<SentDate xsi:nil="true" />
<ReminderDate xsi:nil="true" />
<Documents>
<Document>
<Id>517783</Id>
<Title>Example document</Title>
<ModifiedDate>2016-01-08T16:09:37.15</ModifiedDate>
<ModifiedBy>...</ModifiedBy>
<FileType>doc</FileType>
<ContentType>application/msword</ContentType>
<Size>71680</Size>
<Link href="..."
rel="self"
title="Example document" />
</Document>
</Documents>
<Link href="..."
rel="self"
title="Example matter" />
<Link href="..."
rel="http://cbrain.com/casefile/rel/structure"
title="Complete matter structure" />
</Matter>
+87
+
+Documents
Document resource
+This resource represents the meta data for a single document in F2. The actual binary content is
contained
+in
+a
+different
+resource
+linked
+by
+the
+link
+relation
+http://cbrain.com/casefile/rel/content .
+Location
+Documents can be located directly by ID using the URL template found in the service index. In
addition to this there are links from a matter to all the documents on the matter.
+Lookup by document ID
+The link relation http://cbrain.com/casefile/rel/document-by-id identifies a URL template for
looking up documents by ID. The template uses the template parameter id for the document ID.
+A GET on the generated URL will return a redirect to the corresponding document resource.
+Example link from service document
+{
"http://cbrain.com/casefile/rel/document-by-id":
{
href: "http://.../{id}",
title: "Get document by ID"
}
}
+88
+
+Properties
+89
+
+Table 36. Document properties
+Name
+Description
+Id
+int (read-only)
Internal identifier.
+Title
+string (255 characters)
Document title.
+ModifiedDate
+DateTime (read-only)
Date and time the document was last modified.
+Description
+string
Document description.
+FileType
+string (read-only)
Document file type (file name extension as for instance "pdf" or "doc"
without preceding dot). The file type is set automatically on document
creation.
+ContentType
+string (read-only)
Document mime type (for instance application/pdf ). The document
type is set automatically on document creation.
+FileSize
+int (read-only)
Size of document (number of bytes).
+PreferredAttachmentFormat
+string
Preferred format for attaching the document to its matter when
sending. Possible values are "PDF" and "Original" .
+90
+
+Table 36. Document properties
+Name
+Description
+Link
+List of Link (read-only)
One or more links to other related resources.
+The XML root element is <Document> .
+Document example
+<Document xmlns="http://cbrain.com/casefile/schema/">
<Id>280016</Id>
<Title>Test document</Title>
<ModifiedDate>2022-03-30T08:49:16.27</ModifiedDate>
<ModifiedBy>
<Name>Case Worker 1</Name>
<EMail>test@cbrain.com</EMail>
<Link href="..."
rel="self"
type="application/vnd.cbrain.casefile+xml" />
<Type>User</Type>
<Id>634396</Id>
<PartyNumber>2000001001</PartyNumber>
<CPRCVR />
<CVR_P />
</ModifiedBy>
<Description>Blah blah ...</Description>
<FileType>html</FileType>
<ContentType>text/html</ContentType>
<Size>31</Size>
<PreferredAttachmentFormat />
<OutputManagerTemplateType>None</OutputManagerTemplateType>
<Link href="..."
rel="self"
type="application/vnd.cbrain.casefile+xml" />
<Link href="..."
rel="up"
type="application/vnd.cbrain.casefile+xml" />
<Link href="..."
rel="alternate"
type="application/vnd.cbrain.f2.client" />
<Link href="..."
rel="http://cbrain.com/casefile/rel/content" />
<Link href="..."
rel="http://cbrain.com/casefile/rel/upload-validation" />
<Link href="..."
rel="http://cbrain.com/casefile/rel/text-content" />
</Document>
+Create new document
+A document including binary content may be created using the Post Once Exactly pattern (see
Data manipulation). Follow the link named http://cbrain.com/casefile/rel/create-document
from a specific matter in order to add the document to that matter.
+91
+
+Table 37. Input parameters for creating a document
+Name
+Description
+Title
+string (required, 255 characters)
The title of the new document. This will override the Content-
Disposition attribute filename and should be used to supply a
human readable document title.
+We recommend that Title is used to supply a document title without
the file extension such that a file named "Document.pdf" will be shown
as "Document" in the F2 client.
+Title may also include UTF-8 characters which is not possible with
+the filename attribute of the Content-Disposition element in
multipart encodings.
+Description
+string
Document description.
+PreferredAttachmentFormat
+string
Preferred format for attaching the document to its matter when
sending. Possible values are "PDF" and "Original" .
+File
+binary data
The actual binary file data to be uploaded. The filename-extension of
+Content-Disposition attribute filename is used to define the file
+type, so be careful to supply an informative filename extension, as F2
otherwise will have trouble to display the content correctly.
+TemplateKey
+string
As an alternative to providing file content with the File property, the
document may be generated from an F2 template. TemplateKey
specifies the path of the template in the F2 template tree (as shown in
the template properties in the F2 client).
+OutputManagerTemplateType
+string
Specifies how the document can be used with the output manager
("Fjernprint" in Danish). Possible values are:
+none
+this document cannot be sent via the output manager.
+MainDocument
+this document can be sent as the main document.
+Attachment
+this document can be sent as an attachment.
+There is no need to supply any reference to the parent matter — that is embedded in the URL of
the factory resource.
+92
+
+Example request for creating a new document
+POST /document-create-url HTTP/1.1
Content-Length: 0
+> HTTP/1.1 201 Created
> Location: /document-create-poc-url
> Content-Length: 0
+POST /document-create-poc-url HTTP/1.1
Accept: application/vnd.cbrain.casefile+xml
Content-Type: multipart/form-data; boundary=b00d75a3-bccc-4f5b-978b-225e55c5b521
+--b00d75a3-bccc-4f5b-978b-225e55c5b521
Content-Disposition: form-data; name="Title"
Content-Type: text/plain; charset=utf-8
+File and Template example with UTF-8 emoji 😀 in title
--b00d75a3-bccc-4f5b-978b-225e55c5b521
Content-Disposition: form-data; name="File"; filename="my-document.txt"
Content-Type: application/octet-stream
+... binary data ...
--b00d75a3-bccc-4f5b-978b-225e55c5b521
Content-Disposition: form-data; name="TemplateKey"
Content-Type: text/plain; charset=utf-8
+Standard/Template1
--b00d75a3-bccc-4f5b-978b-225e55c5b521--
+Get binary content
+Follow the link relation http://cbrain.com/casefile/rel/content from the document meta data
and issue an GET request to get the binary content of the document.
+Get PDF content
+Follow the link relation http://cbrain.com/casefile/rel/pdf-content from the document meta
data and issue an GET request to get the PDF content of the document. The link is only included in
the meta data if a PDF representation exists.
+Get flattened PDF content
+Follow the link relation http://cbrain.com/casefile/rel/pdf-content-flattened from the
document meta data and issue an GET request to get the flattened PDF content of the document.
The link is only included in the meta data if a PDF representation exists.
+Get text content
+Follow the link relation http://cbrain.com/casefile/rel/text-content from the document meta
data and issue an GET request to get the text content of the document. The link is only included in
the meta data if text content has been extracted from the document. The text content will contain
all text elements in the original document extracted as separate words in a text document.
+93
+
+Modify document meta data
+Document meta data may be modified by issuing an PATCH request targeted at the document
resource URL.
+Example PATCH request with headers
+PATCH /document-url HTTP/1.1
Accept: application/vnd.cbrain.casefile+xml
Content-Type: application/json-patch+json
+[
{"value":"New document title","op":"replace","path":"/Title"},
{"value":"New description","op":"replace","path":"/Description"}
]
+Modifying binary content
+The binary content of a document may be replaced by following the link relation
+http://cbrain.com/casefile/rel/content from the document meta data and issue an PUT
+request at the content URL, including the binary document content in the HTTP body.
+Upload validation
+The internal upload validation mechanism of F2 may be invoked by looking up the validation URL
template from the link relation http://cbrain.com/casefile/rel/upload-validation in the
document meta data or in the links of a matter. The document template contains the following two
parameters which need to be replaced in the URL before issuing an GET to the resulting URL:
+Table 38. Upload validation URL parameters
+Name
+Description
+filename
+string
Filename of document to upload.
+size
+int
Size, in bytes, of document to upload.
+94
+
+Table 39. Upload validation result properties
+Name
+Description
+Result
+string
The validation result. Possible values are "Valid" , "ValidWithWarnings" and
+"Invalid" . If the result is "ValidWithWarnings" the user should be asked for
+confirmation if possible.
+Messages
+List of Message (string)
One or more warnings or error messages if the result is "ValidWithWarnings" or
+"Invalid"` . Each Message contains a string. If possible, these messages should
+be shown to the user.
+Link
+List of Link (read-only)
One or more links to other related resources.
+Upload validation request example
+GET .../upload-validation-url?filename=My+document.docx&size=10000 HTTP/1.1
Accept: application/vnd.cbrain.casefile+xml
+Upload validation response example
+HTTP/1.1 200 OK
Content-Type: application/vnd.cbrain.casefile+xml
+<UploadValidation xmlns="http://cbrain.com/casefile/schema/">
<Result>ValidWithWarnings</Result>
<Messages>
<Message>The document you are uploading is very large</Message>
</Messages>
<Link href="..." rel="up" title="Matter" />
</UploadValidation>
+Delete document
+A document may be deleted simply by issuing an HTTP DELETE request to the document meta data
URL.
+95
+
+Table 40. Expected link relations
+Rel
+Description
+self
+up
+Link to parent matter.
+http://cbrain.com/casefile/rel/content
+Link to binary document content.
+http://cbrain.com/casefile/rel/upload-
+Link to upload validation, used for validation before
+validation
+updating the document. See Upload validation.
+http://cbrain.com/casefile/rel/text-
+Link to textual document content (it should be noted
+content
+that this operation runs asynchronously, see section
12.60 for clarification).
+http://cbrain.com/casefile/rel/pdf-
+Link to PDF rendering of content (if a PDF version is
+content
+available).
+96
+
+Chats
Chat resource
+This resource represents a single F2 chat with all chat entries included.
+Location
+Chats are located by following the link relation http://cbrain.com/casefile/rel/chats from a
matter. This leads to a resource (see Chats) containing links to all chats on the matter — follow
each link to get the chat resource.
+Properties
Table 41. Chat properties
+Name
+Description
+Id
+int (read-only)
Internal identifier.
+Participants
+List of Participant
One or more participants of the chat communication.
+Participants.Participant.Party
+PartyItem (read-only)
A party who is a participant of the chat.
+Participants.Participant.HasSeen
+bool (read-only)
Indication of whether or not the participant has seen/read the
chat.
+Entries
+List of Entry
One or more chat entries (i.e. messages in the chat).
+Entries.Entry.Text
+string (read-only)
The message text of the chat entry.
+Entries.Entry.CreatedBy
+PartyItem (read-only)
The creator of the message.
+Entries.Entry.CreatedDate
+DateTime (read-only)
The creation date of the message.
+Link
+List of Link (read-only)
One or more links to other related resources.
+The XML root element is <Chat> .
+97
+
+Chat example
+<Chat xmlns="http://cbrain.com/casefile/schema/">
<Id>10514</Id>
<Participants>
<Participant>
<Party>
<Name>Brian Ipsum Hansen</Name>
<Link ... rel="self" title="Brian Ipsum Hansen" />
</Party>
<HasSeen>true</HasSeen>
</Participant>
<Participant> ... </Participant>
...
</Participants>
<Entries>
<Entry>
<Id>6798</Id>
<Text>Are we ready to go?</Text>
<CreatedBy>
<Name>Brian Ipsum Hansen</Name>
<EMail>bih@thecompany.net</EMail>
<Link ... />
</CreatedBy>
<CreatedDate>2016-01-12T11:27:13.16</CreatedDate>
</Entry>
<Entry>
<Id>7185</Id>
<Text>Yes, I think so.</Text>
<CreatedBy>
<Name>Karin Ingemann Petersen</Name>
<EMail>kip@thecompany.net</EMail>
<Link ... />
</CreatedBy>
<CreatedDate>2016-01-12T11:28:31.007</CreatedDate>
</Entry>
</Entries>
<Link ... rel="self" title="Chat" />
<Link ... rel="up" title="Parent matter" />
<Link ... rel="http://cbrain.com/casefile/rel/add-chat-entry"
title="Add entry" />
<Link ... rel="http://cbrain.com/casefile/rel/add-chat-participants"
title="Add participants" />
<Link ... rel="http://cbrain.com/casefile/rel/remove-chat-participants"
title="Remove participants" />
</Chat>
+Add chat entry
+A chat entry may be created using the Post Once Exactly pattern (see Data manipulation). Follow
the link relation http://cbrain.com/casefile/rel/add-chat-entry from an existing chat to locate
the relevant POE resource.
+98
+
+Table 42. Input parameters for adding a chat entry
+Name
+Description
+Text
+string
The text content of the new entry.
+Add chat entry example
+POST /chat-entry-add-url HTTP/1.1
Content-Length: 0
+> HTTP/1.1 201 Created
> Location: /chat-entry-add-poe-url
> Content-Length: 0
+POST /chat-entry-add-poe-url HTTP/1.1
Accept: application/vnd.cbrain.casefile+xml
Content-Type: application/x-www-form-urlencoded
+Text=Thank+you
+> HTTP/1.1 200 OK
> Content-Type: application/vnd.cbrain.casefile+xml
> Location: /chat-url
> Content-Length: 3139
> ... XML representation of resulting chat ...
+Add chat participants
+Follow the link relation http://cbrain.com/casefile/rel/add-chat-participants from an existing
chat to locate the resource for adding chat participants. Then issue an POST request containing the
list of participant references.
+Multiple POST requests with the same participants will only result in the creation of one occurrence
of each participant.
+Table 43. Input parameters for adding chat participants
+Name
+Description
+Participants
+List of PartyReference
Participants to be added to the chat/note.
+There is no need to supply any reference to the parent chat — that is embedded in the URL of the
resource.
+Add chat participants example
+POST /chat-participants-add-url HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 136
+Participants%3a0.PartyNo=117&Participants%3a0.PickFirstMatch=false&Participants%3a1.Login=Mr+W
hite&Participants%3a1.PickFirstMatch=false
+99
+
+Remove chat participants
+Follow the link relation http://cbrain.com/casefile/rel/remove-chat-participants from an
existing chat to locate the action resource for removing chat participants. Then issue an POST
request containing the list of participant references.
+Multiple POST requests with the same participants is allowed (with no additional effect) as
removing a party that is not a participant has no effect.
+Table 44. Input parameters for removing chat participants
+Name
+Description
+Participants
+List of PartyReference
Participants to be removed from the chat.
+There is no need to supply any reference to the parent chat — that is embedded in the URL of the
resource.
+Remove chat participants example
+POST /chat-participants-remove-url HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 136
+Participants%3a0.PartyNo=117&Participants%3a0.PickFirstMatch=false&Participants%3a1.Login=Mr+W
hite&Participants%3a1.PickFirstMatch=false
+Chats
+This resource represents a list of condensed chats of a matter. The condensed chats contain only
the last entry/message on the chat. For each condensed chat the full chat with all entries can be
reached via the self link.
+Location
+The chat list is located by following the link relation http://cbrain.com/casefile/rel/chats from
a matter.
+Properties
+The chat list has one <Chat> element for each chat in the list. Each chat contains the following
properties:
+100
+
+Table 45. Chat list entry properties
+Name
+Description
+Id
+int
Internal identifier.
+LastEntry
+Entry
The last entry/message on the chat.
+LastEntry.Text
+string
The last message text of the chat.
+LastEntry.CreatedBy
+PartyItem
The creator of the last message.
+LastEntry.CreatedDate
+DateTime
The creation date of the last message.
+Chat.Link
+List of Link
Contains a self link to the full chat.
+Link
+List of Link
One or more links to other related resources.
+The XML root element is <Chats> .
+Chat list example
+<Chats xmlns="http://cbrain.com/casefile/schema/">
<Chat>
<Id>10514</Id>
<LastEntry>
<Text>The scope is extended to also cover human resources</Text>
<CreatedBy>
<Name>Karin Ingemann Petersen</Name>
<EMail> kip@thecompany.net</EMail>
<Link href="..." type="application/vnd.cbrain.casefile+xml"
rel="self" title="Karin Ingemann Petersen" />
</CreatedBy>
<CreatedDate>2016-01-12T11:28:31.007</CreatedDate>
</LastEntry>
<Link href="..." type="application/vnd.cbrain.casefile+xml"
rel="self" title="Full chat" />
</Chat>
<Chat>
<Id>10525</Id>
<LastEntry>
...
</LastEntry>
<Link ... />
</Chat>
<Link href="..." type="application/vnd.cbrain.casefile+xml"
rel="self" title="Chats" />
<Link href="..." type="application/vnd.cbrain.casefile+xml"
rel="up" title="Parent matter" />
</Chats>
+101
+
+Add new chat
+A new chat may be created using the Post Once Exactly pattern (see Data manipulation). Follow
the link named http://cbrain.com/casefile/rel/create-chat from a specific matter in order to
add the chat to that matter.
+Table 46. Input parameters for adding a chat
+Name
+Description
+Text
+string
The text content of the first entry in the new chat.
+Participants
+List of PartyReference named Participant
A list of PartyReferences used to identify who is included in the chat. Note that
the chat creator is added implicitly and does not need to appear in the
Participants list.
+Add chat example
+POST /chat-create-url HTTP/1.1
Content-Length: 0
+> HTTP/1.1 201 Created
> Location: /chat-create-poe-url
> Content-Length: 0
+POST /chat-create-poe-url HTTP/1.1
Accept: application/vnd.cbrain.casefile+xml
Content-Type: application/x-www-form-urlencoded
Content-Length: 327
+*** Line breaks included for readability ***
Text=Please+take+a+look+at+this
&Participants%3a0.Login=Sagsbehandler1
&Participants%3a0.PickFirstMatch=false
&Participants%3a1.Login=Sagsbehandler24
&Participants%3a1.PickFirstMatch=false
&Participants%3a2.PartyNo=2000000002
&Participants%3a2.PickFirstMatch=false
&Participants%3a3.PartyNo=125
&Participants%3a3.PickFirstMatch=false
+> HTTP/1.1 201 Created
> Content-Type: application/vnd.cbrain.casefile+xml
> Location: /chat-url
> Content-Length: 3467
> ... Chat XML ...
+102
+
+Notes
Note resource
+This resource represents a single F2 note with all note entries included.
+Location
+Notes are located by following the link relation http://cbrain.com/casefile/rel/notes from a
matter or case. This leads to a resource (see Notes) containing links to all notes on the
matter/case — follow each link to get the note resource.
+Properties
Table 47. Note properties
+Name
+Description
+Id
+int (read-only)
Internal identifier.
+Participants
+List of Participant
One or more participants of the note communication.
+Participants.Participant.Party
+PartyItem (read-only)
A party who is a participant of the note.
+Participants.Participant.HasSeen
+bool (read-only)
Indication of whether or not the participant has seen/read the
note.
+Entries
+List of Entry
One or more note entries.
+Entries.Entry.Text
+string (read-only)
The text of the note entry.
+Entries.Entry.CreatedBy
+PartyItem (read-only)
The creator of the note entry.
+Entries.Entry.CreatedDate
+DateTime (read-only)
The creation date of the note entry.
+Link
+List of Link (read-only)
One or more links to other related resources.
+The XML root element is <Note> .
+103
+
+Note example
+<Note xmlns="http://cbrain.com/casefile/schema/">
<Id>10513</Id>
<Participants>
<Participant>
<Party>
<Name>Brian Ipsum Hansen</Name>
<Link href="..." type="application/vnd.cbrain.casefile+xml"
rel="self" title="Brian Ipsum Hansen" />
</Party>
<HasSeen>true</HasSeen>
</Participant>
<Participant> ... </Participant>
...
</Participants>
<Entries>
<Entry>
<Id>6758</Id>
<Text>This file describes the time line of the project.</Text>
<CreatedBy>
<Name>Brian Ipsum Hansen</Name>
<EMail>bih@thecompany.net</EMail>
<Link ... />
</CreatedBy>
<CreatedDate>2016-01-12T11:27:13.16</CreatedDate>
</Entry>
<Entry>
<Id>6785</Id>
<Text>The scope is extended to also cover human resources</Text>
<CreatedBy>
<Name>Karin Ingemann Petersen</Name>
<EMail>kip@thecompany.net</EMail>
<Link ... />
</CreatedBy>
<CreatedDate>2016-01-12T11:28:31.007</CreatedDate>
</Entry>
</Entries>
<Link ... rel="self" title="Note" />
<Link ... rel="up" title="Parent matter" />
<Link ... rel=http://cbrain.com/casefile/rel/add-note-entry
title="Add entry" />
<Link ... rel=http://cbrain.com/casefile/rel/add-note-participants
title="Add participants" />
<Link ... rel=http://cbrain.com/casefile/rel/remove-note-participants
title="Remove participants" />
</Note>
+Add note entry
+A note entry may be created using the Post Once Exactly pattern (see Data manipulation). Follow
the link relation http://cbrain.com/casefile/rel/add-note-entry from an existing note to locate
the relevant POE resource.
+104
+
+Table 48. Input parameters for adding a note entry
+Name
+Description
+Text
+string
The text content of the new entry.
+Add note entry example
+POST /note-entry-add-url HTTP/1.1
Content-Length: 0
+> HTTP/1.1 201 Created
> Location: /note-entry-add-poe-url
> Content-Length: 0
+POST /note-entry-add-poe-url HTTP/1.1
Accept: application/vnd.cbrain.casefile+xml, application/vnd.cbrain.casefile+xml
Content-Type: application/x-www-form-urlencoded
Content-Length: 14
+Text=Thank+you
+> HTTP/1.1 200 OK
> Content-Type: application/vnd.cbrain.casefile+xml
> Location: /note-url
> Content-Length: 3168
> ... XML representation of resulting note ...
+Add note participants
+Follow the link relation http://cbrain.com/casefile/rel/add-note-participants from an existing
note to locate the resource for adding note participants. Then issue an POST request containing
the list of participant references.
+Multiple POST requests with the same participants will only result in the creation of one occurrence
of each participant.
+Table 49. Input parameters for adding note participants
+Name
+Description
+Participants
+List of PartyReference
Participants to be added to the note/note.
+There is no need to supply any reference to the parent note — that is embedded in the URL of the
resource.
+Add note participants example
+POST /note-participants-add-url HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 136
+Participants%3a0.PartyNo=117&Participants%3a0.PickFirstMatch=false&Participants%3a1.Login=Mr+W
hite&Participants%3a1.PickFirstMatch=false
+105
+
+Remove note participants
+Follow the link relation http://cbrain.com/casefile/rel/remove-note-participants from an
existing note to locate the action resource for removing note participants. Then issue an POST
request containing the list of participant references.
+Multiple POST requests with the same participants is allowed (with no additional effect) as
removing a party that is not a participant has no effect.
+Table 50. Input parameters for removing note participants
+Name
+Description
+Participants
+List of PartyReference
Participants to be removed from the note.
+There is no need to supply any reference to the parent note — that is embedded in the URL of the
resource.
+Remove note participants example
+POST /note-participants-remove-url HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 136
+Participants%3a0.PartyNo=117&Participants%3a0.PickFirstMatch=false&Participants%3a1.Login=Mr+W
hite&Participants%3a1.PickFirstMatch=false
+Notes
+This resource represents a list of condensed notes of a matter or case. The condensed notes
contain only the last entry on the note. For each condensed note the full note with all entries can
be reached via the self link.
+Location
+The note list is located by following the link relation http://cbrain.com/casefile/rel/notes from
a matter/case.
+Properties
+The note list has one <Note> element for each note in the list. Each note contains the following
properties:
+106
+
+Table 51. Note list entry properties
+Name
+Description
+Id
+int
Internal identifier.
+LastEntry
+Entry
The last entry on the note.
+LastEntry.Text
+string
The last entry text of the note.
+LastEntry.CreatedBy
+PartyItem
The creator of the last entry.
+LastEntry.CreatedDate
+DateTime
The creation date of the last note entry.
+Note.Link
+List of Link
Contains a self link to the full note.
+Link
+List of Link
One or more links to other related resources.
+The XML root element is <Notes> .
+Note list example
+<Notes xmlns="http://cbrain.com/casefile/schema/">
<Note>
<Id>10514</Id>
<LastEntry>
<Text>The scope is extended to also cover human resources</Text>
<CreatedBy>
<Name>Karin Ingemann Petersen</Name>
<EMail> kip@thecompany.net</EMail>
<Link href="..." type="application/vnd.cbrain.casefile+xml"
rel="self" title="Karin Ingemann Petersen" />
</CreatedBy>
<CreatedDate>2016-01-12T11:28:31.007</CreatedDate>
</LastEntry>
<Link href="..." type="application/vnd.cbrain.casefile+xml"
rel="self" title="Full note" />
</Note>
<Note>
<Id>10525</Id>
<LastEntry>
...
</LastEntry>
<Link ... />
</Note>
<Link href="..." type="application/vnd.cbrain.casefile+xml"
rel="self" title="Notes" />
<Link href="..." type="application/vnd.cbrain.casefile+xml"
rel="up" title="Parent matter" />
</Notes>
+107
+
+Add new note
+A new note may be created using the Post Once Exactly pattern (see Data manipulation). Follow
the link named http://cbrain.com/casefile/rel/create-note from a specific matter or case in
order to add the note to it.
+Table 52. Input parameters for adding a note
+Name
+Description
+Text
+string
The text content of the first entry in the new note.
+Participants
+List of PartyReference named Participant
A list of PartyReferences used to identify who is included in the note. Note that
the note creator is added implicitly and does not need to appear in the
Participants list.
+Add note example
+POST /note-create-url HTTP/1.1
Content-Length: 0
+> HTTP/1.1 201 Created
> Location: /note-create-poe-url
> Content-Length: 0
+POST /note-create-poe-url HTTP/1.1
Accept: application/vnd.cbrain.casefile+xml
Content-Type: application/x-www-form-urlencoded
Content-Length: 327
+*** Line breaks included for readability ***
Text=This+is+the+conclusion
&Participants%3a0.Login=Sagsbehandler1
&Participants%3a0.PickFirstMatch=false
&Participants%3a1.Login=Sagsbehandler24
&Participants%3a1.PickFirstMatch=false
&Participants%3a2.PartyNo=2000000002
&Participants%3a2.PickFirstMatch=false
&Participants%3a3.PartyNo=125
&Participants%3a3.PickFirstMatch=false
+> HTTP/1.1 201 Created
> Content-Type: application/vnd.cbrain.casefile+xml
> Location: /note-url
> Content-Length: 3467
> ... Note XML ...
+108
+
+Party resources
+109
+
+Common Party properties
+110
+
+Table 53. Common Party properties
+Name
+Description
+Id
+int
Internal identifier.
+Name
+string
Name of party.
+PartyNumber
+int
A number that identifies a party in F2. This number is visible in the F2 client as
opposed to the Id which is internal (not visible). It is the same as PartyNo used
in party references.
+Relation
+string
The party’s relation to a specific matter or case. Examples of relations could be
Sender, CaseWorker, ResponsibleUnit, Approver, etc. The relation values are
common to all F2 installations.
+PartyType
+string
The party type title assigned to the party in the context of a specific matter or
case. The party types are F2 customer specific i.e. configured for each F2
installation.
+PartyTypeKey
+string
The identifier of the party type.
+Email
+string (100 characters)
The email address of the party.
+CVRCPR
+string (20 characters)
An external identification number for the party. For example in a Danish
installation it could be the nationwide CVR number of a company or the
nationwide CPR number of a citizen.
+CVR_P
+string (20 characters)
An external identification number for the party, to be combined with the CVRCPR
number. For example, in a Danish installation it could be combined with the
nationwide CVR number of a company, where one company with the same CVR
number can have different branches that each have a unique CVR_P number.
+Phone
+string (50 characters)
The phone number of the party.
+LocalNumber
+string (10 characters)
Local extension to the phone number of the party.
+MobilePhone
+string (50 characters)
The mobile phone number of a party.
+Address1
+string (255 characters)
The (first line of the) address of the party. Usually this contains the street name
+111
+
+Table 53. Common Party properties
+Name
+Description
+and house number.
+Address2
+string (255 characters)
The (second line of the) address of the party.
+PostalCode
+string (40 characters)
The postal code of the party’s address.
+ProtectedAddress
+bool
Whether or not this party is marked for having a protected address.
+City
+string (100 characters)
The city of the party’s address.
+CountryCode
+string (10 characters)
The country code of the party’s address.
+Telefax
+string (50 characters)
The fax number of the party.
+IsRegistryVersion
+bool
Indicates whether this party representation is the current registry version or a
snapshot of the original.
+Link
+List of Link
One or more links to other related resources.
+Active
+bool
Whether or not this party is marked as active in F2.
+Organization
+This resource represents an organization in F2.
+Properties
+An organization includes only the common properties listed above.
+The XML root element is <Organization> .
+112
+
+Table 54. Expected link relations
+Rel
+Description
+self
+Link to self
+up
+Link to the parent of the party. A link only exists if there
is a parent for the party.
+down
+Link to a list of the children of the party.
+http://cbrain.com/casefile/rel/field-
+Link to additional field data specified for the party. See
+data
+F2-REST Documentation.
+http://cbrain.com/casefile/rel/registry
+Link to current registry version of the party. This link is
only available on the original snapshot version of the
party.
+External party
+This resource represents an external party in F2.
+Properties
+In addition to the properties listed above, an external party representation includes the following
properties:
+Table 55. External party properties
+Name
+Description
+ContactPerson
+string (255 characters)
This property can be used to store the name of a contact person related to the
party.
+PostageGroup
+string (100 characters)
Postage group.
+SynchronizationKey
+string (255 characters)
A synchronization key related to the party. Also known as the External Party
Number from the Party Registry within F2.
+Web
+string (100 characters)
This property can be used for storing a web address related to the party.
+Organization
+F2-REST Documentation
The organization which the external party belongs to.
+The XML root element is <External> .
+113
+
+External party example
+<External xmlns="http://cbrain.com/casefile/schema/">
<Id>400775</Id>
<Name>The Chocolate Company</Name>
<Active>true</Name>
<PartyType>PropertyOwner</PartyType>
<Address1>Helevejen 1</Address1>
<Address2 />
<City>Egebjerg</City>
<CountryCode>DK</CountryCode>
<CVRCPR>12345678</CVRCPR>
<CVR_P>0987654321</CVR_P>
<EMail>tcc@example.dk</EMail>
<LocalNumber>123</LocalNumber>
<MobilePhone>12345678</MobilePhone>
<Phone>12345678</Phone>
<PostalCode>2751</PostalCode>
<ProtectedAddress>false</ProtectedAddress >
<SynchronizationKey>xpq123</SynchronizationKey >
<Telefax>22334455</Telefax>
<Web>http://cbrain.dk</Web>
<Organization>
<Name>Parent company</Name>
<Type>Unit</Type>
<Id>2156</Id>
<PartyNumber>20</PartyNumber>
<CPRCVR>12344321</CPRCVR>
<CVR_P>1234554321</CVR_P>
<Name>Parent company</Name>
<Link href="..."
rel="self"
type="application/vnd.cbrain.casefile+xml"
title="Parent company" />
</Organization>
<Link href="..."
rel="self"
type="application/vnd.cbrain.casefile+xml"
title="The Chocolate Company" />
</External>
+114
+
+Table 56. Expected link relations
+Rel
+Description
+self
+Link to self
+up
+Link to the parent of the party. A link only exists if there
is a parent for the party.
+down
+Link to a list of the children of the party.
+http://cbrain.com/casefile/rel/field-
+Link to additional field data specified for the party. See
+data
+F2-REST Documentation.
+http://cbrain.com/casefile/rel/registry
+Link to current registry version of the party. This link is
only available on the original snapshot version of the
party.
+http://cbrain.com/casefile/rel/move-
+Link for moving the external party. This will update the
+external-party
+Organization property. See Move external party.
+Create external party
+An external party may be created using the Post Once Exactly pattern (see Data manipulation).
Follow the link named http://cbrain.com/casefile/rel/create-external-party from the service
index and POST the following parameters to the referenced resource.
+115
+
+Table 57. Input parameters for creating an external party
+Name
+Description
+Name
+string (255 characters)
The name of the external party to be created.
+ParentOrganization
+PartyReference
This property specifies the organization that the external party is to be created
under. If this property is not specified, a standard organization will be selected
instead.
+Address1
+string
+Address2
+string
+City
+string
+ContactPerson
+string
+CountryCode
+string
+CVRCPR
+string
+CVR_P
+string
+EMail
+string
+LocalNumber
+string
+MobilePhone
+string
+Phone
+string
+PostageGroup
+string
+PostalCode
+string
+ProtectedAddress
+string
+Relation
+string
+SynchronizationKey
+string
+Telefax
+string
+Web
+string
+116
+
+External party creation example
+POST party-create-url HTTP/1.1
Content-Length: 0
+> HTTP/1.1 201 Created
> Location: party-create-poe-url
> Content-Length: 0
+POST party-create-poe-url HTTP/1.1
Accept: application/vnd.cbrain.casefile+xml
Content-Type: application/x-www-form-urlencoded
+ContactPerson=George Locus&
PostageGroup=Group+A&
SynchronizationKey=637840753521414881&
Web=https%3A%2F%2Fwww.dr.dk&
Address1=The+Road+1&
Address2=&
City=Copenhagen&
CountryCode=DK&
CVRCPR=130896-1234&
CVR_P=9876543210&
EMail=hello%40cbrain.net&
LocalNumber=1234&
MobilePhone=12345678&
Name=Adam+Adler&
Phone=78907890&
PostalCode=1234&
ProtectedAddress=false&
Telefax=SomeFaxNo
+Move external party
+The location of an external party can be changed from one organization to another. Look up the
"party moving" resource through the link relation http://cbrain.com/casefile/rel/move-party
found in the external party’s link collection. Then issue an POST request to the resource with the
following input parameters:
+Table 58. Input parameters for moving an external party
+Name
+Description
+Destination
+PartyReference
A party reference specifying the new organization of the external party.
+Move external party example
+POST move-party-url HTTP/1.1
Content-Type: application/x-www-form-urlencoded
+Destination.PartyNo=11163&Destination.PickFirstMatch=false
+117
+
+User
+This resource represents an F2 user belonging to an organization.
+Properties
+In addition to the properties listed above, a user representation includes the following properties:
+Table 59. External party properties
+Name
+Description
+Initials
+string (255 characters)
The initials of the user.
+Organization
+F2-REST Documentation
The organization which the user belongs to.
+The XML root element is <User> .
+User example
+<User xmlns="http://cbrain.com/casefile/schema/">
<Id>400776</Id>
<Name>The Boss</Name>
<Organization>
<Name>Parent company</Name>
<Type>Unit</Type>
<Id>2156</Id>
<PartyNumber>20</PartyNumber>
<CPRCVR>12344321</CPRCVR>
<CVR_P>1234554321</CVR_P>
<Name>Parent company</Name>
<Link href="..."
rel="self"
type="application/vnd.cbrain.casefile+xml"
title="Parent company" />
</Organization>
<Link href="..."
rel="self"
type="application/vnd.cbrain.casefile+xml"
title="The Boss" />
</User>
+118
+
+Table 60. Expected link relations
+Rel
+Description
+self
+Link to self
+up
+Link to the parent of the party. A link only exists if there
is a parent for the party.
+http://cbrain.com/casefile/rel/field-
+Link to additional field data specified for the party. See
+data
+F2-REST Documentation.
+http://cbrain.com/casefile/rel/registry
+Link to current registry version of the party. This link is
only available on the original snapshot version of the
party.
+119
+
+Party collection
Party collection resource
+This resource represents a collection of parties such as all the parties related to a case. The
collection represents the original version of the parties.
+The XML representation of the collection uses different XML element names for the different types
of parties.
+There are different elements representing a party; a User element, an Organization element, an
External party element, and possibly other kinds of party elements in future versions. These party
elements differ by the properties they may have.
+Properties
Table 61. Partylist properties
+Name
+Description
+Items
+mixed
Contains one or more parties. The party sub elements can be one or more of
User elements, Organization elements, External party elements — and possibly
other kinds in future versions.
+Link
+List of Link (read-only)
One or more links to other related resources.
+The XML root element is <Parties> .
+Party list example
+<Parties xmlns="http://cbrain.com/casefile/schema/">
<Items>
<External>
...
</External>
<Organization>
...
</Organization>
...
</Items>
<Link href="..."
rel="self"
type="application/vnd.cbrain.casefile+xml"
title="Parties" />
<Link href="... "
rel="up"
type="application/vnd.cbrain.casefile+xml"
title="Parent" />
</Parties>
+120
+
+Table 62. Expected link relations
+Rel
+Description
+self
+up
+Link to the parent of the party list (such as the case which the parties are
referenced from).
+121
+
+Approvals
Approval resource
+This resource represents a single approval process associated with a matter.
+Location
+An
+approval
+associated
+with
+a
+matter
+can
+be
+found
+by
+following
+the
+link
+http://cbrain.com/casefile/rel/approval from the matter’s link collection. Approvals can also
+be found by looking up on approval ID directly.
+Lookup by approval ID
+The link relation http://cbrain.com/casefile/rel/approval-by-id , found in the service index,
identifies a URL template for looking up approvals by ID. The template uses the template
parameter id for the approval ID.
+A GET on the generated URL will return a redirect to the corresponding approval resource.
+Example link from service document
+{
"http://cbrain.com/casefile/rel/approval-by-id":
{
href: "http://.../{id}",
title: "Get approval by ID"
}
}
+122
+
+Properties
+123
+
+Table 63. Approval properties
+Name
+Description
+Id
+int
Internal approval identifier.
+MatterId
+int
Associated matter identifier.
+ApprovalType
+Enumeration
Approval type.
+Deadline
+DateTime
Approval deadline.
+Urgent
+bool
Urgent or non-urgent approval.
+Text
+string
Text content of approval process document.
+Responsible
+Responsible
Details about responsible party.
+Responsible.Party
+PartyItem
Party responsible for the approval process.
+Responsible.Comment
+string
Responsible party’s comment.
+CreatedDate
+DateTime
Timestamp for when the approval process was created.
+StartedDate
+DateTime
Timestamp for when the approval process was started.
+FinishedDate
+DateTime
Timestamp for when the approval process was finished (either approved or
cancelled).
+Status
+string
Status of the approval process. Possible values are:
+Created
+InProgress
+Cancelled
+Approved
+StatusDetails
+string
Human readable text describing in-depth status of the approval process.
+124
+
+Table 63. Approval properties
+Name
+Description
+StatusDescription
+string
Human readable text describing status of the approval process.
+The XML root is Approval .
+Approval example
+<Approval xmlns="http://cbrain.com/casefile/schema/">
<Id>9290</Id>
<MatterId>279243</MatterId>
<ApprovalType>
<Title>Type 1</Title>
<Path>Type 1</Path>
<Code>Type_1</Code>
<Link href="..."
rel="http://cbrain.com/casefile/rel/enum-type"
type="application/vnd.cbrain.casefile+xml" />
</ApprovalType>
<Deadline>2020-11-30T00:00:00</Deadline>
<Urgent>true</Urgent>
<Text>... HTML content ...</Text>
<Responsible>
<Party>
<Name>Maria Suneson</Name>
<EMail>test@cbrain.com</EMail>
<Link href="..."
rel="self"
type="application/vnd.cbrain.casefile+xml" />
<Type>User</Type>
<Id>407189</Id>
<PartyNumber>2000001001</PartyNumber>
<CPRCVR />
<CVR_P />
</Party>
</Responsible>
<CreatedDate>2022-03-25T12:27:39.183</CreatedDate>
<StartedDate xsi:nil="true" />
<FinishedDate xsi:nil="true" />
<Status>Created</Status>
<StatusDetails>Approval process not yet started</StatusDetails>
<StatusDescription>In progress</StatusDescription>
<Link href="..."
rel="self"
type="application/vnd.cbrain.casefile+xml" />
<Link href="..."
rel="up"
type="application/vnd.cbrain.casefile+xml" />
<Link href="..."
rel="http://cbrain.com/casefile/rel/pdf-content"
type="application/pdf" />
<Link href="..."
rel="http://cbrain.com/casefile/rel/start-approval"
type="application/vnd.cbrain.casefile+xml" />
</Approval>
+125
+
+Table 64. Expected link relations
+Rel
+Description
+self
+up
+Link to parent matter.
+http://cbrain.com/casefile/rel/start-
+Link to approval process starter resource.
+approval
+http://cbrain.com/casefile/rel/pdf-
+Link to approval process description in PDF format.
+content
+Create new approval
+An approval process may be created using the Post Once Exactly pattern (see Data manipulation).
Follow the link named http://cbrain.com/casefile/rel/create-approval from a specific matter
in order to add the approval process to that matter.
+126
+
+Table 65. Input parameters for creating an approval process
+Name
+Description
+ApprovalProcessTemplate_Id
+int
Internal database identifier for approval process template.
+ApprovalProcessTemplate_ExternalId
+int
External identifier for approval process template.
+Deadline
+DateTime
Deadline for approval.
+ApprovalTypeId
+string
External enumeration ID for approval type.
+Urgent
+bool
Urgent indication for approval process.
+Steps
+Step
List of steps in approval process.
+Steps.Approvers
+List of PartyReference
List of approvers for approval step.
+Steps.Deadline
+DateTime
Deadline for approval step.
+Steps.SubscribedToActions
+string
Comma-separated list of subscriptions for the assigned
approvers. Possible subscription values are:
+NoExtraNotifications
+WhenRevisitingAfterReturning
+WhenStepChanges
+WhenFinallyApproved
+WhenCommentIsAdded
+AutoStart
+bool
Pass true to start approval process immediately after
creation.
+127
+
+Approval process creation example
+POST approval-creation-url HTTP/1.1
Content-Length: 0
+> HTTP/1.1 201 Created
> Location: approval-process-poe-url
+POST approval-creation-poe-url HTTP/1.1
Accept: application/vnd.cbrain.casefile+xml
Content-Type: application/x-www-form-urlencoded
+Steps%3a0.Approvers%3a0.PartyNo=66&
Steps%3a0.Approvers%3a0.PickFirstMatch=false&
Steps%3a0.Approvers%3a1.PartyNo=2000001024&
Steps%3a0.Approvers%3a1.PickFirstMatch=false&
Steps%3a0.Deadline=2019-02-02T00%3a00%3a00&
Steps%3a0.SubscribedToActions=WhenCommentIsAdded+%2cWhenRevisitingAfterReturning&
Steps%3a1.Approvers%3a0.PartyNo=2000001003&
Steps%3a1.Approvers%3a0.PickFirstMatch=false&
Steps%3a1.Deadline=2018-03-03T00%3a00%3a00&
AutoStart=false&
ApprovalTypeId=Approval-process-type&
Urgent=true
+Modify approval process
+Approvals cannot, at the time of writing, be modified.
+Start approval process
+An
+approval
+process
+can
+be
+started
+by
+looking
+up
+the
+link
+relation
+http://cbrain.com/casefile/rel/start-approval in the approval’s link collection and then issue
+an empty POST to that resource.
+Table 66. Start approval process response properties
+Name
+Description
+Success
+bool
Success indicator.
+Warnings
+string
Warning message in case of failure.
+Example approval process start request
+POST approval-process-start-url HTTP/1.1
Accept: application/vnd.cbrain.casefile+xml
Content-Length: 0
+128
+
+Example approval process start response
+HTTP/1.1 200 OK
Content-Type: application/vnd.cbrain.casefile+xml
+<ApprovalProcessStartedResult xmlns="http://cbrain.com/casefile/schema/">
<Success>true</Success>
</ApprovalProcessStartedResult>
+129
+
+Enumerations
Enumeration type resource
+This resource represents an enumeration type definition and all of it’s possible enumeration items.
+Location
+Properties
Table 67. Enumeration type properties
+Name
+Description
+Title
+string
Enumeration type title.
+Id
+string
Enumeration type ID.
+Items
+List of enumeration items named Item (see below)
All enumeration items in enumeration. The enumeration type represents the root
of a tree and items represent the nodes under the root.
+The XML root element is EnumerationType .
+Table 68. Enumeration item properties
+Name
+Description
+Title
+string
The title of the enumeration item.
+Path
+string
Represents the enumeration items position in the tree. If the top level item
"ItemTitle" contains the child "ItemTitleChild", then the Path of "ItemTitleChild"
will be "ItemTitle/ItemTitleChild".
+Code
+string
An Id which can be used to find the item in question in other contexts.
+Abbreviation
+string
An Id that was historically used the same way as Code . Often the same as Code
or empty.
+Items
+List of enumeration item named Item
A list of child items. This list represents the items that are the children of the
current enumeration item.
+130
+
+Enumeration type example
+<EnumerationType xmlns="http://cbrain.com/casefile/schema/">
<Title>TypeTitle</Title>
<Id>TypeId</Id>
<Items>
<Item>
<Title>ItemTitle</Title>
<Path>ItemTitle</Path>
<Code>ItemId</Code>
<Abbreviation>ItemId</Abbreviation>
<Items>
<Item>
<Title>ItemTitleChild</Title>
<Path>ItemTitle/ItemTitleChild</Path>
<Code>ItemIdChild</Code>
<Abbreviation>ItemIdChild</Abbreviation>
<Items/>
</Item>
</Items>
</Item>
<Items>
</EnumerationType>
+131
+
+Security group
Security group resource
+This resource represents a security group in F2. These groups can be given access to F2 resources
such as cases and matters, granting access to these resources to each of the group members. As
such, they function to manage the security clearances for groups of users.
+Location
+Security groups can be located using their ID, their synchronization key or their party number.
+Lookup by ID
+A
+security
+group
+can
+be
+accessed
+using
+the
+link
+relation
+http://cbrain.com/casefile/rel/securitygroup-by-id to find the URL template for lookups on
+ID.
+A GET on the generated URL resource will redirect to the appropriate security group resource.
+Example link from service document
+{
"http://cbrain.com/casefile/rel/securitygroup-by-id":
{
href: "http://.../{id}",
title: "Get security group by id"
}
}
+Lookup by syncronization key
+A
+security
+group
+can
+be
+accessed
+using
+the
+link
+relation
+http://cbrain.com/casefile/rel/securitygroup-by-synch-key to find the URL template for
+lookups on synchronization keys.
+A GET on the generated URL resource will redirect to the appropriate security group resource.
+Example link from service document
+{
"http://cbrain.com/casefile/rel/securitygroup-by-synch-key":
{
href: "http://.../{syncKey}",
title: "Get security group by synchronization key"
}
}
+Lookup by party number
+132
+
+A GET on the generated URL resource will redirect to the appropriate security group resource.
+Example link from service document
+{
"http://cbrain.com/casefile/rel/securitygroup-by-party-number":
{
href: "http://.../{partyNumber}",
title: "Get security group by party number"
}
}
+Properties
Table 69. Security group properties
+Name
+Description
+AuthorityTitle
+string (read-only)
The name of the authority the security group belongs under
+GroupName
+string (255 characters)
The name of the security group
+SynchronizationKey
+string (255 characters)
The synchronization key
+Id
+int (read-only)
Internal security group identifier.
+Party Number
+int (read-only)
The party number of the security group.
+IsActive
+bool (read-only)
Indicates whether or not the security group is active.
+PartyItems
+List<PartyItem>
The users currently in the security group.
+133
+
+Security group example
+<SecurityGroupItem
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://cbrain.com/casefile/schema/">
<AuthorityTitle>Departementet</AuthorityTitle>
<GroupName>SG-SyncKey</GroupName>
<SynchronizationKey>C8163116-7031-47FA-9D54-0E6880827B4D</SynchronizationKey>
<IsActive>true</IsActive>
<Id>634576</Id>
<PartyNumber>230</PartyNumber>
<Link href="..." rel="self" title="SG-SyncKey" />
<Link href="..." rel="http://cbrain.com/casefile/rel/securitygroup-add-member" title="Add
member" />
<Link href="..." rel="http://cbrain.com/casefile/rel/securitygroup-remove-member"
title="Remove member" />
<Link href="..." rel="http://cbrain.com/casefile/rel/securitygroup-activate" title="Activate
security group member" />
<Link href="..." rel="http://cbrain.com/casefile/rel/securitygroup-deactivate"
title="Deactivate security group" />
<PartyItems>
<PartyItem>
<Name>CaseWorkerPartyWithNameInBothMinisteries</Name>
<EMail />
<Link href="..." rel="self" title="CaseWorkerPartyWithNameInBothMinisteries" />
<Type>User</Type>
<Id>634581</Id>
<PartyNumber>235</PartyNumber>
<CPRCVR />
<CVR_P />
</PartyItem>
<PartyItem>
<Name>DobbeltAnsat</Name>
<EMail>DobbeltAnsat@cbrain.dk</EMail>
<Link href="..." rel="self" title="DobbeltAnsat" />
<Type>User</Type>
<Id>634574</Id>
<PartyNumber>228</PartyNumber>
<CPRCVR />
<CVR_P />
</PartyItem>
</PartyItems>
</SecurityGroupItem>
+134
+
+Table 70. Expected link relations
+Rel
+Description
+self
+Link to self
+http://cbrain.com/casefile/rel/securitygroup-
+Adds member to security group. See Add
+add-member
+member to security group.
+http://cbrain.com/casefile/rel/securitygroup-
+Removes member from group See Remove
+remove-member
+member from security group.
+http://cbrain.com/casefile/rel/securitygroup-
+Sets the status of an inactive security group to
+activate
+active (accepts POST requests).
+http://cbrain.com/casefile/rel/securitygroup-
+Sets the status of an active security group to
+deactivate
+inactive (accepts POST requests).
+Modify security group
+Some properties of a security group may be modified by issuing a PATCH request targeted at the
security group resource URL. Only the GroupName, SynchronizationKey and PartyItems list can be
changed for a security group using a patch request. For the Name and Synchronizationkey, string
values are accepted. For PartyItems, an array of PartyReferences is needed to change the current
members of a security group to the new list.
+Example PATCH request with headers
+PATCH /securitygroup-url HTTP/1.1
Accept: application/vnd.cbrain.casefile+xml
Content-Type: application/json-patch
+[
{"value":"Changed sync key","op":"replace","path":"/SynchronizationKey"},
{"value":"Changed title","op":"replace","path":"/GroupName"},
{"value":[{"PartyNo":26},{"PartyNo":28}], "op":"replace", "path":"/PartyItems"},
]
+Create new security group
+A security group may be created using the Post Once Exactly pattern (see Data manipulation).
Form a POST request on the link http://cbrain.com/casefile/rel/securitygroup-create from
the service index to locate the POE resource for creating a security group.
+135
+
+Table 71. Input parameters for creating a security group
+Name
+Description
+AuthorityId
+int (required)
The Id of the authority the security group will belong to.
+Name
+string (required, 255 characters)
The name of the new security group.
+SynchonizationKey
+string
The synchronization key of the security group
+Add member to security group
+Adding a member to a security group may be done using the Post Once Exactly pattern (see Data
manipulation). Form a POST request on the link http://cbrain.com/casefile/rel/securitygroup-
add-member from the service index to locate the POE resource for adding a member to a security
group. Despite the POE pattern, adding a the same member to a security group more than once
has no effect.
+Table 72. Input parameters for adding members to a security group
+Name
+Description
+Party
+PartyReference (required)
The user to be added to the security group
+Remove member from security group
+Removing a member from a security group may be done by using a POST request on the link
received from the link relation http://cbrain.com/casefile/rel/securitygroup-remove-member .
Removing a security group member from a group multiple times has no effect.
+Table 73. Input parameters for removing members from a security group
+Name
+Description
+Party
+PartyReference (required)
The user to be removed from the security group
+ Task guides
= Task guide state
+Task guide state resource
+This resource represents the current state of a task guide — that is, the visibility and completeness
of tasks and processes as well as the values of fields and variables used by the task guide. The
data is only intended for reading.
+136
+
+Location
+The
+state
+of
+a
+task
+guide
+can
+be
+found
+by
+following
+the
+link
+relation
+http://cbrain.com/casefile/rel/taskguide-state from the resource representing the related case.
+137
+
+Properties
+138
+
+Table 74. Task guide state properties
+Name
+Description
+TaskGuideKey
+string
Task guide key (file name of task guide file).
+Processes
+List
List of processes.
+Processes.Process.ItemKey
+string
Item key identifying a single process.
+Processes.Process.Visible
+bool
Visibility of single process.
+Processes/Process/Tasks
+List
List of tasks in process.
+Processes.Process.Tasks.Task.ItemKey
+string
Item key identifying a single task.
+Processes.Process.Tasks.Task.Visible
+bool
Visibility of single task.
+Processes.Process.Tasks.Task.Complete
+bool
Completeness of single task.
+Fields
+List
List of fields and task guide variables.
+Fields.Field.Name
+string
Name of field.
+Fields/Field/IsList
+bool
Indicates if the field is a list or a simple value. If true then
the element <List> contains the rows of the list,
otherwise the element <Value> contains the simple
value.
+Fields/Field/Value
+mixed
Simple value of field (booleans, strings, dates and
numbers as well as sets).
+Fields/Field/IsWritable
+bool
Indicates whether or not the field is writable by the
current user.
+Fields/Field/List
+List
List of rows.
+Fields.Field.List.Row
+List
List of fields included in the row.
+139
+
+Table 74. Task guide state properties
+Name
+Description
+A single named field and its value. Row fields have the same (recursive)
structure as a single Fields/Field element.
+The XML root element is <TaskGuideState> .
+140
+
+Task guide state example
+<TaskGuideState xmlns="http://cbrain.com/casefile/schema/">
<TaskGuideKey>DemoTaskGuide</TaskGuideKey>
<Processes>
<Process>
<ItemKey>P1</ItemKey>
<Visible>true</Visible>
<Tasks>
<Task>
<ItemKey>P1_T1</ItemKey>
<Visible>false</Visible>
<Complete>false</Complete>
</Task>
<Task>
<ItemKey>P1_T2</ItemKey>
<Visible>true</Visible>
<Complete>false</Complete>
</Task>
</Tasks>
</Process>
...
</Processes>
<Fields>
<Field>
<Name>DemoName</Name>
<IsList>false</IsList>
<Value xsi:type="xsd:string">Hari Seldon</Value>
<List xsi:nil="true" />
</Field>
<Field>
<Name>DemoAttribute</Name>
<IsList>false</IsList>
<Value xsi:type="Set" Enumeration="AttributeSet">
<Elements>
<Element>A1</Element>
<Element>A2</Element>
</Elements>
</Value>
<List xsi:nil="true" />
</Field>
<Field>
<Name>DemoList</Name>
<IsList>true</IsList>
<Value xsi:nil="true" />
<List>
<Row>
<Field>
<Name>Name</Name>
<IsList>false</IsList>
<Value xsi:type="xsd:string">Gaal Dornick</Value>
<List xsi:nil="true" />
</Field>
</Row>
<Row>
<Field>
<Name>Name</Name>
<IsList>false</IsList>
<Value xsi:type="xsd:string">Salvor Hardin</Value>
<List xsi:nil="true" />
+141
+
+</Row>
</List>
</Field>
</Fields>
</TaskGuideState>
+Execute single task
+The actual semantics of executing a task depends on the type of task involved — it simply
corresponds to the action that would happen when activating the primary task button or a specific
action button in the desktop client UI.
+Executing a task may result in various related actions or scripts on the task being executed too —
precisely in the same way as it works on the desktop client.
+A single task can be executed by looking up the "execute task handler" linked to a case by the link
relation http://cbrain.com/casefile/rel/taskguidetasks-execute . Follow this link and issue an
HTTP POST to it with the parameters shown below.
+The "execute task handler" is a Post Once Exactly resource and as such it is necessary to POST
twice to this resource as described in Data manipulation. The response does although behave a
little bit different as no resources are created — thus the HTTP response status code is 200 where
after the POE status must be decoded from the <Status> element of the response.
+Table 75. Inputs for executing a task
+Name
+Description
+ItemKey
+string
The item key of a task to execute.
+ActionName
+string
The name of an action to execute. For use with <Action> tasks containing
multiple actions.
+142
+
+Execute task example
+POST /execute-task-url HTTP/1.1
Content-Length: 0
+> HTTP/1.1 201 Created
> Content-Type: text/html
> Location: /execute-task-poe-url
> ... HTML content for browser based API exploration ...
+POST /execute-task-poe-url HTTP/1.1
Accept: application/vnd.cbrain.casefile+xml
Content-Type: application/x-www-form-urlencoded
+ItemKey=T_SetName
+> HTTP/1.1 200 OK
> Content-Type: application/vnd.cbrain.casefile+xml
> ... XML response ...
+Table 76. Execute task response properties
+Name
+Description
+Status
+string
Status of operation. See table below for possible values.
+Message
+string
Message to show end-user. The message may be empty if there is nothing
interesting to present.
+Warnings
+List of strings named Warning
List of warnings to show end-user. The list may be empty if there is nothing
interesting to present.
+Table 77. Possible values for Status
+Name
+Description
+Ok
+Task was executed without issues.
+RequireMoreInfo
+Task cannot be completed without supplying more information (this is currently
not supported by F2-REST).
+PartialOk
+Task execution involved data from a list, but the task was only executed for
some of the elements in the list.
+AlreadyCompleted
+Task execution was completed by an earlier post-once-exactly operation.
+143
+
+Execute task response example
+<ExecuteTaskResult xmlns="http://cbrain.com/casefile/schema/">
<Status>Ok</Status>
<Message>Some message</Message>
<Warnings>
<Warning>Some warning</Warning>
</Warnings>
</ExecuteTaskResult>
+Allowed methods
+GET
+Get a representation of the handler. This will return an HTML page describing the resource for
use with browser-based exploration of the API.
+POST
+Execute task using the Post Once Exactly pattern.
+Complete single task
+Completing a task via F2-REST corresponds to checking off the "Complete" checkbox beside a task
in the desktop client. Completing a task may result in various related actions or scripts on the task
being executed too — precisely in the same way as it works on the desktop client.
+A single task can be completed by looking up the "complete task handler" linked to a case by the
link relation http://cbrain.com/casefile/rel/taskguidetasks-complete. Follow this link and issue an
HTTP POST to it with the parameters shown below.
+The "complete task handler" is a Post Once Exactly resource and as such it is necessary to POST
twice to this resource as described in Data manipulation. The response does although behave a
little bit different as no resources are created — thus the HTTP response status code is 200 where
after the POE status must be decoded from the <Status> element of the response.
+Table 78. Inputs for completing a task
+Name
+Description
+ItemKey
+string
The item key of a task to complete.
+Complete
+bool
Specifies whether to complete the task or uncomplete it.
+144
+
+Complete task example
+POST /complete-task-url HTTP/1.1
Content-Length: 0
+> HTTP/1.1 201 Created
> Content-Type: text/html
> Location: /complete-task-poe-url
> ... HTML content for browser based API exploration ...
+POST /complete-task-poe-url HTTP/1.1
Accept: application/vnd.cbrain.casefile+xml
Content-Type: application/x-www-form-urlencoded
+ItemKey=T_SetName&Complete=true
+> HTTP/1.1 200 OK
> Content-Type: application/vnd.cbrain.casefile+xml
> ... XML response ...
+Table 79. Complete task response properties
+Name
+Description
+Status
+string
Status of operation. See table below for possible values.
+Message
+string
Message to show end-user. The message may be empty if there is nothing
interesting to present.
+Table 80. Possible values for Status
+Name
+Description
+Ok
+Task was completed without issues.
+AlreadyCompleted
+Task was completed by an earlier post-once-exactly operation.
+Complete task response example
+<CompleteTaskResult xmlns="http://cbrain.com/casefile/schema/">
<Status>Ok</Status>
<Message>Some message</Message>
</CompleteTaskResult>
+Allowed methods
+GET
+Get a representation of the handler. This will return an HTML page describing the resource for
use with browser-based exploration of the API.
+POST
+145
+
+Complete (or uncomplete) task using the Post Once Exactly pattern.
+Execute OnSave actions for single task
+Executing OnSave actions on a task via F2-REST corresponds to pressing "Edit" and then saving
the content of that task. Executing the OnSave actions may result in various related actions or
scripts on the task being executed too — precisely in the same way as it works on the desktop
client.
+A single task can be invoked by looking up the "save task handler" linked to a case by the link
relation http://cbrain.com/casefile/rel/taskguidetasks-save. Follow this link and issue an HTTP POST
to it with the parameters shown below.
+The "save task handler" is a Post Once Exactly resource and as such it is necessary to POST twice
to this resource as described in Data manipulation. The response does although behave a little bit
different as no resources are created — thus the HTTP response status code is 200 where after the
POE status must be decoded from the <Status> element of the response.
+Table 81. Inputs for executing OnSave actions for a task
+Name
+Description
+ItemKey
+string
The item key of a task to invoke.
+Save task example
+POST /save-task-url HTTP/1.1
Content-Length: 0
+> HTTP/1.1 201 Created
> Content-Type: text/html
> Location: /save-task-poe-url
> ... HTML content for browser based API exploration ...
+POST /save-task-poe-url HTTP/1.1
Accept: application/vnd.cbrain.casefile+xml
Content-Type: application/x-www-form-urlencoded
+ItemKey=T_EditDetails
+> HTTP/1.1 200 OK
> Content-Type: application/vnd.cbrain.casefile+xml
> ... XML response ...
+146
+
+Table 82. Save task response properties
+Name
+Description
+Status
+string
Status of operation. See table below for possible values.
+Message
+string
Message to show end-user. The message may be empty if there is nothing
interesting to present.
+Table 83. Possible values for Status
+Name
+Description
+Ok
+Task was saved without issues.
+AlreadySaved
+Task was saved by an earlier post-once-exactly operation.
+Complete save response example
+<SavekResult xmlns="http://cbrain.com/casefile/schema/">
<Status>Ok</Status>
<Message>Some message</Message>
</SaveTaskResult>
+Allowed methods
+GET
+Get a representation of the handler. This will return an HTML page describing the resource for
use with browser-based exploration of the API.
+POST
+Execute OnSave actions for task using the Post Once Exactly pattern.
+Execute task guide script
+A task guide script can be executed by looking up the "execute script handler" linked to a case by
the link relation http://cbrain.com/casefile/rel/taskguidescripts-execute . Follow this link and
issue a POST to it with the parameters shown below.
+The execute script handler is a Post Once Exactly resource and as such it is necessary to POST
twice to this resource as described in Data manipulation.
+Table 84. Inputs for executing a script
+Name
+Description
+ScriptName
+string
The name of the script.
+147
+
+Execute script example
+POST /execute-script-url HTTP/1.1
Content-Length: 0
+> HTTP/1.1 201 Created
> Content-Type: text/html
> Location: /execute-script-poe-url
> ... HTML content for browser based API exploration ...
+POST /execute-script-poe-url HTTP/1.1
Accept: application/vnd.cbrain.casefile+xml
Content-Type: application/x-www-form-urlencoded
+ScriptName=NameOfScript
+> HTTP/1.1 200 OK
+Result structure
+Due to the nature of how task guide scripts works. This operation is not expected to return an error
status code, in case an error occured in one of the executed scripts. This is because the operation
could be a partial success. The result structure needs to be inspected in order to determine which
scripts has failed.
+The result structure is shown in the table Properties of ExecuteTaskGuideScriptResult .
+Table 85. Properties of ExecuteTaskGuideScriptResult
+Name
+Description
+Message
+string
Status of operation. Possible values are:
+This operation has already completed.
+Executed taskguide script.
+Results
+List of ScriptResults named ScriptResult
Recursive list of results from running the script. See ScriptResult below. If a
task in the script contains a reference to another script which is run succesfully,
then Results.Count > 1 else Results.Count == 1 .
+148
+
+Table 86. Properties of ScriptResult
+Name
+Description
+CaseId
+Long
NodeId of the case which the script is run on.
+ScriptName
+String
Name of the script.
+TaskResults
+List of TaskResult and ActionTaskResult
List of results of each task run. See TaskResult below. If action type is
+ExecuteAction then the type will be ActionTaskResult which extends
TaskResult .
+IsOk
+Bool
Is used to indicate if the entire script has failed. Normal errors are marked in a
specific TaskResult or ActionTaskResult . Some errors, such at exceeding the
maximum number of derived scripts, occur before a specific task is executed. As
such the error is indicated here.
+Message
+String
If the property IsOk is false this property describes what the error was.
+149
+
+Table 87. Properties of TaskResult
+Name
+Description
+TaskType
+String
Specifies the type of the task. Possible values are:
+CompleteTask — a complete or uncomplete task.
+ExecuteTask — execute a task.
+ExecuteAction — execute an action on a task.
+DeleteReplyLink — Delete reply link on selfservice task.
+Exception — representing a failed task.
+TaskKey
+String
Unique key of the task
+IgnoreErrors
+Bool
+true if the task was run with the IgnoreErrors flag
+ActionFailed
+Bool
+true if the task failed.
+IsOk
+Bool
+true if the task succeded without errors or if IgnoreErrors is true .
+Errors
+List of String
List of error messages if the task or related tasks failed.
+Table 88. Properties of ActionTaskResult extending TaskResult
+Name
+Description
+ActionKey
+String
Unique key of the action.
+150
+
+Execute taskguide script response example
+<ExecuteTaskGuideScriptResult xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://cbrain.com/casefile/schema/">
<Message>Executed TaskGuideScript.</Message>
<Results>
<ScriptResult>
<CaseId>12345</CaseId>
<ScriptName>ExampleScript</ScriptName>
<IsOk>true</IsOk>
<TaskResults>
<TaskResult>
<TaskType>ExecuteTask</TaskType>
<TaskKey>ExampleTask</TaskKey>
<IsOk>true</IsOk>
<IgnoreErrors>false</IgnoreErrors>
<ActionFailed>false</ActionFailed>
<Errors />
</TaskResult>
<ActionTaskResult>
<TaskType>ExecuteAction</TaskType>
<TaskKey>ExampleTask2</TaskKey>
<IsOk>true</IsOk>
<IgnoreErrors>false</IgnoreErrors>
<ActionFailed>false</ActionFailed>
<Errors />
<ActionKey>ExampleAction</ActionKey>
</ActionTaskResult>
</TaskResults>
</ScriptResult>
<ScriptResult>
<CaseId>54321</CaseId>
<ScriptName>ExampleScript2</ScriptName>
<IsOk>true</IsOk>
<Message>Exceeded the maximum number of derived scripts.</Message>
<TaskResults/>
</ScriptResult>
</Results>
</ExecuteTaskGuideScriptResult>
+Allowed methods
+GET
+Get a representation of the handler. This will return an HTML page describing the resource for
use with browser-based exploration of the API.
+POST
+Execute task guide script using the Post Once Exactly pattern.
+ Extensions
= Case guide data
+A core concept of F2 case guides, is to be able to store a mixed set of fields (named values) in the
case guide. This case data can be manipulated through F2-REST where it is refered to as
+151
+
+"extension records" — where each record is an XML blob storing all of the case guide data related
to the case.
+In addition to the global case guide data, it is also possible to store named lists of records where
each record represents a single row in the list. These lists corresponds to the lists in case guide
data.
+The system allows multiple named extension records for each case. In practice though, only the
records named CaseInfo is used — these represent the case guide data.
+Record data, rows and fields
+The data stored in a record, consists of a list of fields — each of which contains a field name and a
field value.
+A row in a list is the same as a record with an additional row identifier.
+In the following sections we use the data types Record , Row and Field :
+Table 89. Record properties
+Name
+Description
+Fields
+List of Field
List of all fields in the record.
+Table 90. Row properties
+Name
+Description
+Id
+string
Row identifier (GUID). All rows have unique identifiers irrespective of which lists
they are contained in. Use the identifier when updating, deleting or replacing
rows.
+Fields
+List of Field
List of all fields in the row.
+Table 91. Field properties
+Name
+Description
+@name
+string
Name of field (XML attribute).
+Value
+mixed
Value of field.
+Value@xsi:type
+string
Value type.
+152
+
+Field values
+Field values are encoded using XML schema data types as documented in [XMLTypes] and
[XMLSchema].
+Table 92. Used namespaces
+Alias
+Namespace
+xsi
+http://www.w3.org/2001/XMLSchema-instance
+xsd
+http://www.w3.org/2001/XMLSchema
+Table 93. Supported types and XML encoding
+Name
+Example
+bool
+<Value xsi:type="xsd:boolean">false</Value>
+int
+<Value xsi:type="xsd:int">10</Value>
+decimal
+<Value xsi:type="xsd:decimal">35.50</Value>
+double
+<Value xsi:type="xsd:double">20.12</Value>
+string
+<Value xsi:type="xsd:string">Hej mor</Value>
+datetime
+<Value xsi:type="xsd:dateTime">2013-08-27T10:20:30+02:00</Value>
+set
+<Value xsi:type="Set" Enumeration="ATest">
<Elements>
<Element>A</Element>
<Element>B</Element>
<Element>C</Element>
</Elements>
</Value>
+Extension record
+This resource represents a single F2 extension record with links to the lists related to it.
+Location
+The link relation http://cbrain.com/casefile/rel/extension-record-by-name , found in the links
from a case, identifies a URL template for looking up extension records on that case by name. The
template uses the template parameter recordName for the record name. Use the record name
+CaseInfo for the standard case guide data.
+A GET on the generated URL will return a redirect to the corresponding extension record resource.
+153
+
+Example link from case
+<Link href="http://record-url/{recordName}"
rel="http://cbrain.com/casefile/rel/extension-record-by-name"
type="application/vnd.cbrain.casefile+xml" />
+Properties
Table 94. Extension record properties
+Name
+Description
+Id
+int
Record identifier.
+Name
+string
Record name.
+LastUpdated
+DateTime
Last updated time.
+Fields
+List of Field
List of fields stored in the record.
+Lists
+List of List
List of lists related to record.
+Lists.List.Name
+string
Name of list.
+Lists.List.Link
+List of Link
Link to related resource. Follow self link to get list content.
+Link
+List of Link
One or more links to other related resources.
+154
+
+Extension record example
+<Record xmlns="http://cbrain.com/casefile/schema/">
<Id>13016</Id>
<Name>CaseInfo</Name>
<Fields>
<Field name="Name">
<Value xsi:type="xsd:string">Ofelia</Value>
</Field>
<Field name="EMail">
<Value xsi:type="xsd:string">example@cbrain.dk</Value>
</Field>
<Field name="Address1Field">
<Value xsi:nil="true" />
</Field>
</Fields>
<Link href="..."
rel="self"
type="application/vnd.cbrain.casefile+xml"
title="Record" />
<Lists>
<List Name="Books">
<Link href="..." rel="self" type="application/vnd.cbrain.casefile+xml" />
</List>
<List Name="Tickets">
<Link href="..." rel="self" type="application/vnd.cbrain.casefile+xml" />
</List>
</Lists>
</Record>
+Table 95. Expected link relations
+Rel
+Description
+self
+http://cbrain.com/casefile/rel/update
+Link to resource for updating a single record.
+http://cbrain.com/casefile/rel/update-
+Link to resource for updating lists in a record.
+lists
+Create new extension record
+An extension record may be created by posting to an appropriate resource. Follow the link named
+http://cbrain.com/casefile/rel/create-record from a case to locate the resource. The Post
+Once Exactly pattern (see Data manipulation) is not required here as it impossible to create more
than one named record for each case.
+The input format must be XML to be able to encode all the different value types.
+155
+
+Table 96. Input parameters for creating an extension record
+Name
+Description
+Name
+string
Name of record. Use CaseInfo for case guide data.
+Record
+Record
Record containing the initial fields for the extension record.
+Extension record creation example
+POST create-record-url HTTP/1.1
Accept: application/vnd.cbrain.casefile+xml
Content-Type: application/xml
+<NewRecordArgs
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="http://cbrain.com/casefile/schema/">
<Record>
<Fields>
<Field name="A">
<Value xsi:type="xsd:int">999</Value>
</Field>
</Fields>
</Record>
<Name>CaseInfo</Name>
</NewRecordArgs>
+Update extension record
+The link relation http://cbrain.com/casefile/rel/update , found on a record, leads to a resource
for updating the record. Either POST or PUT new field values to this resource — a POST will merge
the new fields into the existing record whereas a PUT will clear the existing record first before
adding the fields passed to the resource.
+The input format must be XML to be able to encode all the different value types.
+Table 97. Input parameters for updating an extension record
+Name
+Description
+Record
+Record
Record containing the fields for the extension record.
+156
+
+Extension record update example
+POST update-record-url HTTP/1.1
Accept: application/vnd.cbrain.casefile+xml
Content-Type: application/xml
+<UpdateRecordArgs
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="http://cbrain.com/casefile/schema/">
<Record>
<Fields>
<Field name="A">
<Value xsi:type="xsd:string">Hello world</Value>
</Field>
<Field name="K">
<Value xsi:type="xsd:double">100.234</Value>
</Field>
</Fields>
</Record>
</UpdateRecordArgs>
+Delete extension record
+An extension record my be deleted simply by issuing a DELETE request at the extension record
resource.
+Extension list
+This resource represents all the rows of a single list.
+Location
+Lists are referenced from an extension record in it’s <Lists> element - from which it is necessary
to follow the self link to get the actual list content. It looks like this:
+Extension record example with links to lists
+<Record xmlns="http://cbrain.com/casefile/schema/">
<Id>13016</Id>
<Name>CaseInfo</Name>
<Fields>
...
</Fields>
<Lists>
<List Name="Books">
<Link href="..." rel="self" type="application/vnd.cbrain.casefile+xml" />
</List>
<List Name="Tickets">
<Link href="..." rel="self" type="application/vnd.cbrain.casefile+xml" />
</List>
</Lists>
</Record>
+157
+
+Properties
Table 98. List properties
+Name
+Description
+Name
+string
Name of list.
+Rows
+List of Row
All rows in the list.
+The XML root element is <List> .
+List example
+<List xmlns="http://cbrain.com/casefile/schema/">
<Name>Books</Name>
<Rows>
<Row>
<Id>cc1d9d03-f042-424d-b1cc-7adcdf0da59d</Id>
<Fields>
<Field name="Title">
<Value xsi:type="xsd:string">Rice and fall of pi</Value>
</Field>
</Fields>
</Row>
<Row>
<Id>ddd02eea-31fd-4fc5-ab69-ad1fc12202de</Id>
<Fields>
<Field name="Title">
<Value xsi:type="xsd:string">A history of real numbers</Value>
</Field>
</Fields>
</Row>
</Rows>
<Link href="..."
rel="up"
type="application/vnd.cbrain.casefile+xml"
title="Parent" />
</List>
+Update list
+Follow the link relation http://cbrain.com/casefile/rel/update-lists from an extension record
to find a resource for updating the lists on the record. Then use the Post Once Exactly pattern (see
Data manipulation) to issue a set of operations on the lists to append, delete, update or replace
rows.
+The input format must be XML to be able to encode all the different value types.
+158
+
+Table 99. Update list inputs
+Name
+Description
+Actions
+List of Append, Update, Replace, Delete or DeleteList
List of operations on lists.
+The XML root element is UpdateListArgs .
+Table 100. Append properties
+Name
+Description
+ListName
+string
Name of list to append row to. If the list does not exist already it will be created
automatically. The new row is appended to the end of the list.
+Row
+Row
Row to append. New rows MUST be assigned a globally unique row identifier
before appending it.
+Table 101. Update properties
+Name
+Description
+Row
+Row
Row to update. Use the row identifier to specify which row to update.
Updating a row only touches the fields referenced in the row input.
+Since row identifiers are globally unique, it is not necessary to supply a list
name.
+Table 102. Replace properties
+Name
+Description
+Row
+Row
Row to replace. Use the row identifier to specify which row to replace.
Replacing a row removes all existing fields in the row before adding the
fields from the input.
+Since row identifiers are globally unique, it is not necessary to supply a list
name.
+159
+
+Table 103. Delete properties
+Name
+Description
+Id
+string
Identifies which row to delete.
+Since row identifiers are globally unique, it is not necessary to supply a list
name.
+Table 104. DeleteList properties
+Name
+Description
+ListName
+string
Identifies a list to delete completely.
+Table 105. Update list response properties
+Name
+Description
+Ok
+bool
Update status.
+Message
+string
Optional error message.
+The XML root element is UpdateListResult .
+160
+
+List update example
+POST update-list-url HTTP/1.1
Content-Length: 0
+> HTTP/1.1 201 Created
> Location: update-list-url-poe
> Content-Length: 0
+POST update-list-url-poe HTTP/1.1
Accept: application/vnd.cbrain.casefile+xml
Content-Type: application/xml
+<UpdateListArgs xmlns="http://cbrain.com/casefile/schema/">
<Actions>
<Update>
<Row>
<Fields>
<Field name="Name">
<Value xsi:type="xsd:string">Frank</Value>
</Field>
</Fields>
<Id>c97445e3-2e72-4a60-9ed0-cd82f212017a</Id>
</Row>
</Update>
<Delete>
<Id>0d24d36e-6eeb-4b24-91b8-3b4d5551d4b5</Id>
</Delete>
<Append>
<ListName>Books</ListName>
<Row>
<Fields>
<Field name="Name">
<Value xsi:type="xsd:string">Between numbers</Value>
</Field>
</Fields>
<Id>58eff98a-cb54-421a-99e9-1ab4dd88a028</Id>
</Row>
</Append>
</Actions>
</UpdateListArgs>
+> HTTP/1.1 200 OK
> Content-Type: application/vnd.cbrain.casefile+xml
>
> <UpdateListResult xmlns="http://cbrain.com/casefile/schema/">
> <Ok>true</Ok>
> <Message>Success</Message>
> </UpdateListResult>
+161
+
+Custom XML data
+One way to extend F2, is to store custom XML data associated with cases and matters. The XML
schema for the actual data can be chosen freely - F2 puts no constraint on it. Further more, there is
room for multiple named XML data elements for each case or matter.
+Custom XML data is used by F2 to store data from extension fields embedded in the case and
matter windows.
+Custom XML data resource
+Location
+Custom
+XML
+data
+located
+by
+following
+the
+link
+relation
+http://cbrain.com/casefile/rel/extension-data from a matter or case. This leads to a resource
+containing the custom XML data.
+Properties
+The custom XML data resource contains the following properties:
+Table 106. Custom XML data properties
+Name
+Description
+Extension
+Extension
Zero or more named custom XML data elements.
+Extension.ProcessName
+string
Name of extension.
+Extension.Data
+mixed
Custom XML data.
+Link
+List of Link
One or more links to other related resources.
+The XML root element is Extensions .
+162
+
+Custom XML data example
+<Extensions xmlns="http://cbrain.com/casefile/schema/">
<Extension>
<ProcessName>Abc</ProcessName>
<Data><Size xmlns="http://123">10</Size></Data>
</Extension>
<Extension>
<ProcessName>Xyz</ProcessName>
<Data><Position xmlns="http://123">20,10</Position></Data>
</Extension>
<Link href="…"
rel="self"
type="application/vnd.cbrain.casefile+xml"
title="Extensions" />
<Link href="…"
rel="up"
type="application/vnd.cbrain.casefile+xml"
title="Parent" />
</Extensions>
+Add or update custom XML data
+Follow the link named http://cbrain.com/casefile/rel/create-extension-data to locate a
handler for creating custom XML data. Then issue an POST to the resource with the input
properties described below.
+Multiple POST requests with the same data will only result in the creation of one data set for the
given process name - the last request overwrites earlier data.
+Table 107. Input parameters for creating custom XML data
+Name
+Description
+ProcessName
+string (255 characters)
Process name associated with the custom XML data.
+Data
+string
Actual raw XML payload.
+Add custom XML data example
+POST extension-data-create-url HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 108
+ProcessName=Test&Data=%3cTest+xmlns%3d%22http%3a%2f%2f123%22%3e%3cName%3eAnders%3c%2fName%3e%3
c%2fTest%3e
+Updating matter & case extension fields
+It is possible to update individual extension fields on matters and cases. Matters contain the link
named http://cbrain.com/casefile/rel/update-matter-extension-data and cases contain the
link named http://cbrain.com/casefile/rel/update-case-extension-data . In order to update a
+163
+
+field, perform an POST request to the link. The Post Once Exactly pattern (see Data manipulation)
is not required here as the same POST operation can be performed more than once, to no effect.
+The request body should be formatted as XML. The request body should contain a list of name-
value pairs. The name-value list is merged into the existing extension fields.
+Extension fields update example JSON
+POST update-extension-url HTTP/1.1
Content-Type: application/json
+{
"Fields":[
{
"Name":"FieldName1",
"Value":"FieldValue1"
},
{
"Name":"FieldName2",
"Value":"FieldValue2"
}
]
}
+164
+
+Additional properties
+Data in F2 may also be enriched by associating collections of simple key/value pairs with various
objects (usually parties).
+A person (external party) may for instance be related to a job interview and in this context, we
need to store the applicant’s date of birth. This can be stored as a key/value combination where
the key is "DateOfBirth" and the value is the actual date of birth.
+Additional properties resource
+This resource contains a set of key/value properties that represents additional fields as used in F2’s
party management.
+The key/value properties are represented as application/x-www-form-urlencoded values with
UTF-8 encoding.
+Date values should be formatted according to RFC 3339 "Date and Time on the Internet:
Timestamps". Like for instance 1985-04-12T23:20:50.52Z .
+Location
+The
+additional
+properties
+are
+located
+by
+following
+the
+link
+relation
+http://cbrain.com/casefile/rel/field-data from a matter or case.
+Properties
+There are no predefined properties. All stored properties are returned as application/x-www-form-
urlencoded .
+Additional properties example
+Submitted_ByName=Frank+Monacho&
Submitted_ByPhone=12345678&
Submitted_ByMail=example%40cbrain.com
+Update properties
+Issue a POST to the additional properties resource to add or update fields. The body should contain
an application/x-www-form-urlencoded encoded list of key/value pairs to represent the additional
properties which should be updated. See the additional properties example above.
+Replace all properties
+Issue a PUT to the additional properties resource to clear all fields and add new ones. The body
should contain an application/x-www-form-urlencoded encoded list of key/value pairs to
represent the new properties. See the additional properties example above.
+ Searching
= Filtered case search
+165
+
+Case search resource
+This resource represents a search engine for searching cases by various properties.
+Location
+The
+case
+search
+resource
+can
+be
+found
+by
+following
+the
+link
+relation
+http://cbrain.com/casefile/rel/case-search-filter from the service index.
+A GET on the base URL returns an HTML form for testing the queries.
+Input parameters
Table 108. Input query parameters for case search
+Name
+Description
+caseNumber
+string
+id
+int
+title
+string
+cprNumber
+string
+externalId
+string
+The search result can be represented as either an ATOM feed [ATOM], CSV [CSV] or JSON [JSON] as
controlled by the standard HTTP content negotiation mechanism using the "Accept" header.
+Search request example
+GET case-search-url?cprNumber=311299-1234 HTTP/1.1
Accept: text/csv
+166
+
+Output values
Table 109. Output values for case search
+Name
+Description
+Id
+int
+CaseNumber
+string
+Title
+string
+CprNumber
+string
+ExternalId
+string
+Created`
+DateTime
+Updated`
+DateTime
+alternate
+URL
Link to case in F2-REST.
+Search response example
+HTTP/1.1 200 OK
Content-Type: text/csv
+Id,CaseNumber,Title,CprNumber,ExternalId,Created,Updated,alternate
"279666","2022 - 1172","A test case for case search","311299-1234","P2103568","2022-03-
29T11:00:58","2022-03-29T11:00:58","https://case-url"
+167
+
+Filtered matter search
Matter search resource
+This resource represents a search engine for searching matters by various properties.
+Location
+The
+matter
+search
+resource
+can
+be
+found
+by
+following
+the
+link
+relation
+http://cbrain.com/casefile/rel/matter-search-filter from the service index.
+A GET on the base URL returns an HTML form for testing the queries.
+Input parameters
Table 110. Input query parameters for matter search
+Name
+Description
+matterNumber
+int
+id
+int
+title
+string
+caseNumber
+string
+cprNumber
+string
+The search result can be represented as either an ATOM feed [ATOM], CSV [CSV] or JSON [JSON] as
controlled by the standard HTTP content negotiation mechanism using the Accept header.
+Search request example
+GET matter-search-url?id=&matterNumber=&title=&caseNumber=2022-1170&cprNumber= HTTP/1.1
Accept: text/csv
+168
+
+Output values
Table 111. Output values for matter search
+Name
+Description
+Id
+int
+MatterNumber
+int
+CaseNumber
+string
+CaseTitle
+string
+CprNumber
+string
+Type
+string
+AccessLevel
+string
+Deadline
+DateTime
+Archived
+bool
+Status
+DateTime
+Created`
+DateTime
+Updated`
+DateTime
+alternate
+URL
Link to matter in F2-REST.
+Search response example
+HTTP/1.1 200 OK
Content-Type: text/csv
+Id,MatterNumber,Title,CaseNumber,CprNumber,Type,AccessLevel,Deadline,Archived,Status,Created,U
pdated,alternate
"279655","13249","Test dossier for case 279654","2022 - 1170","","","","","","","2022-03-
29T10:44:18","2022-03-29T10:44:19","https:://matter-url"
+169
+
+OpenSearch document
+OpenSearch [OpenSearch] is a format for describing the web interface of a search engine — in this
case the full text search engine of F2. The format is rather simple — at the core of it there is a URL
template where the search text can be merged into, whereafter the client should perform a GET of
the resulting URL. The server will then return the search result as an ATOM feed [ATOM].
+Table 112. URL template variables for OpenSearch
+Name
+Description
+{searchTerms}
+string
The string to search for.
+{count}
+int
The number of returned search results.
+OpenSearch document example
+<OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/">
<ShortName>Matter search</ShortName>
<Description>Searching by any text for matters in F2</Description>
<Author>cBrain</Author>
<Contact>cbrain@cbrain.dk</Contact>
<Url type="application/atom+xml"
template="http://example.com/search?q={searchTerms}&count={count}" />
</OpenSearchDescription>
+Matter search
+To get the OpenSearch description document for searching for matters, follow the link relation
http://cbrain.com/casefile/rel/matter-search.
+Case search
+To get the OpenSearch description document for searching for matters, follow the link relation
http://cbrain.com/casefile/rel/case-search.
+170
+
+Custom queries
Custom query resource
+This resource represents a customized way to do searches. This may be useful when the search is
more complex and requires detailed knowledge of F2 internal resources that are not part of the
REST API abstraction.
+Usage
+A custom query is build up from a base URL with a query name and added query parameters. The
parameter profile for a given query is defined by a Custom Query description document (as
documented in the internal F2-REST installation manual). The installed custom queries are listed in
the custom query index (found in the service index by looking for the link relation
http://cbrain.com/casefile/rel/custom-query-index).
+If we assume a base URL of http://example.com/custom-queries/THEQUERY for the custom query
named THEQUERY then the search can be executed with parameters P1 = value1 and P2 = value2
using the URL http://example.com/custom-queries/THEQUERY?P1=value1&P2=value2.
+A GET on the base URL returns an HTML form for testing the query.
+The search result can be represented as either an ATOM feed [ATOM], CSV [CSV], XML, JSON or
HTML as controlled by the standard HTTP content negotiation mechanism using the "Accept"
header.
+A custom query named THEQUERY is installed in a designated folder in the F2 REST installation in a
custom query description document called THEQUERY.query.xml.
+CSV example output
+In CSV the column headers matches column names in SQL:
+Bool,Int,Number1,Number2,String1,String2,Date,DateTime,Null
"1","2","3.3","4.4","Abcd","Xyz","2025-08-05T00:00:00","2025-08-05T17:22:45",""
"1","2","3.3","4.4","Abcd","Xyz","2025-08-05T00:00:00","2025-08-05T17:22:45",""
+JSON example output
+In JSON the output is an array of objects where each object has property names that matches the
SQL column names:
+171
+
+{
"value": [
{
"Bool": 1,
"Int": 2,
"Number1": 3.3,
"Number2": 4.4,
"String1": "Abcd",
"String2": "Xyz",
"Date": "2025-08-05T00:00:00+02:00",
"DateTime": "2025-08-05T17:22:45+02:00",
"Null": null
},
{
"Bool": 1,
"Int": 2,
"Number1": 3.3,
"Number2": 4.4,
"String1": "Abcd",
"String2": "Xyz",
"Date": "2025-08-05T00:00:00+02:00",
"DateTime": "2025-08-05T17:22:45+02:00",
"Null": null
}
]
}
+XML example output
+In XML the the output is a list of <Item> elements with sub-elements that matches the SQL column
names:
+172
+
+Custom query as self-service Web Action target
+This resource represents a custom query as described above. It does however transform the query
result into an XML format which the self-service web action expects.
+This version of the query can be accessed in the same manner as normal, and can also take Post
request, with either Url-Form or JSON encoded data. The URL segment "custom-queries" should
also be replaced with "selfservice-webaction". It is important to note that not all custom queries
should be accessed through this URL, as it expects the output to only have one row, which at the
very least has the columns: "Success" and "Message". "Success" should be a Boolean/bit value,
which informs the Web Action whether or not the operation was a success. "Message" is an error
message to be shown in case of failure. Every column besides these two are treated as self-service
properties, which will be updated with the corresponding row value. A value of NULL is however
ignored and the corresponding field is not updated.
+When used as a web action, the custom query supports JWT authorization. Refer to the selv-service
manual for information related to the expected form of the authorization token.
+The custom query will only accept JWT validation if the custom query authorization attribute has
the value "WebActionJwt".
+The JWT token is expected to have the values:
+iss = http://cbrain.com/f2/self-service/
sub = http://cbrain.com/f2/rest/
+The token is only considered valid if the server time has not exceeded the time defined by exp.
+Custom query as taskguide Webpush target
+This resource represents a custom query as described here. Similarly to self-service web action
queries, the result of such a query transforms the result to JSON in a format suitable for the task
guide.
+This version of the query can be accessed in the same manner as normal with the URL segment
"custom-queries" replaced with "taskmanagement-webpush". It is important to note that not all
custom queries should be accessed through this URL, as it expects the output to only have one
row, which at the very least has the columns: "Success" and "Message". "Success" should be a
Boolean/bit value, which informs the Web Action whether or not the operation was a success.
"Message" is an error message to be shown in case of failure. Every column besides these two are
treated as taskguide fields, which will be updated with the corresponding row value. A value of
NULL is however ignored and the corresponding field is not updated.
+When used as a web push, the custom query supports JWT authorization. Refer to the task guide
manual for information related to the expected form of the authorization token.
+The custom query will only accept JWT validation if the custom query authorization attribute has
the value "WebActionJwt".
+173
+
+Receiver = http://cbrain.com/f2/rest/
+11.7 Custom query as self-service validator
+F2-REST implements the "external validator" interface of F2 Self Service.
+As an example, F2-REST may be used by F2 Self-service as a validator to check if a certain user is
allowed to submit a Self Service form. F2 Self-service will then use a self-service validator resource
of F2-REST. The result of the validator indicates if the user can continue or if the F2 Self-service
client should show a message to the user about the failed validation.
+F2 Self-service validators are used in two contexts: 1) For login validation where a message is
shown on the login page, and 2) for page validation where a message is shown in a list together
with other kinds of validation messages e.g. for empty mandatory fields, etc.
+A self-service validator is a specialized search using custom queries. The custom query of a self-
service validator must always return the following properties:
+Table 113. Self-service response properties
+Name
+Description
+IsValid
+int
Validation result represented by 0 (failure) or 1 (success).
+Code
+string
Some custom code describing the validation result. It could, for instance,
describe the reason for failure.
+Message
+string
A message suitable for presentation to a self-service user after performing the
validation. For login validators the message should be html formatted as it will
be included on an html web page. For page validators the message should be a
single line of plain text as it will be included in a standard list of validation errors.
+In order to use a custom query as a self-service validator, the resource URL should be slightly
different than the corresponding custom query URL. For example, if the custom query resource URL
is http://example.com/custom-queries/THEQUERY then the Self Service validator resource URL is
http://example.com/selfservice-validator/THEQUERY.
+A POST on the validator URL returns a validator result (see above) in XML format.
+The input parameters to the validator are specified in the POST content as multipart/form-data.
POST headers to use:
+Accept: application/xml
Content-Type: multipart/form-data
+As for ordinary custom queries, an additional parameter named Authorization may be added in the
POST content (thus this name cannot be used for other parameters). This is used to authorize the
+174
+
+client. The value must match the AuthorizationSecret specified in the descriptor document for the
corresponding installed self-service validator.
+A self-service validator named THEQUERY is installed in the same place as custom queries in a
designated folder in the F2-REST installation in a custom query description document called
THEQUERY.query.xml.
+Custom query for auto completer
+Both F2 Self-service and F2 task guides have an external auto completer feature (read more about
them in their manual). F2-REST implements a handle to use a custom query for those auto
completers. It works the same way as normal custom queries, however the URL segment "custom-
queries" should however be replaced with "external-auto-completer".
+The result is expected to have the columns "Display" and "Value". See for instance the custom
query "auto-completer-get-enum.query.xml" for an example of how to use it for journal plans.
+ Other resources
= Simple collection
+Simple collection resource
+This resource represents a list of items.
+A collection is represented by 1) a set of aggregated collection properties and 2) a list of the items
in the collection.
+The list items are represented by their title together with links to more detailed information.
+The root element is <Collection> . This element contains the following aggregated collection
properties:
+Table 114. Collection properties
+Name
+Description
+Title
+string
The title of the collection.
+Link
+List of Link
One or more links to other related resources.
+The item collection is marked with an <Items> element and contains zero or more <Item>
elements.
+Each <Item> element contains the following properties:
+175
+
+Table 115. Item properties
+Name
+Description
+Id
+string
An identifier for the item.
+Title
+string
The title of the item.
+Link
+List of Link
One or more links to other related resources.
+The XML root element is <Collection> .
+Example collection
+<Collection xmlns="http://cbrain.com/casefile/schema/">
<Title>Documents for matter 'Borgerhenvendelse vedrørende Bjørneklo'</Title>
<Link href="..."
rel="self"
type="application/vnd.cbrain.casefile.collection+xml"
title="Documents" />
<Link href="..."
rel="up"
type="application/vnd.cbrain.casefile+xml"
title="Matter" />
<Items>
<Item>
<Id>378053</Id>
<Title>DossierDocument</Title>
<Link href="..."
rel="self"
type="application/vnd.cbrain.casefile+xml"
title="DossierDocument" />
</Item>
<Item>
<Id>378054</Id>
<Title>Photo2.gif</Title>
<Link href="..."
rel="self"
type="application/vnd.cbrain.casefile+xml"
title="Photo2.gif" />
</Item>
</Items>
</Collection>
+176
+
+Meetings
Meeting resource
+This resource represents a single meeting in F2.
+Location
+Meetings can only be found by URLs supplied other places in F2 (Manager). This may be improved
on in later versions.
+177
+
+Properties
Table 116. Meeting properties
+Name
+Description
+Id
+int (read-only)
Internal identifier.
+MeetingNumber
+string (read-only)
Public visible meeting number (for instance "2012 - 341").
+Title
+string
Meeting title.
+Category
+Enumeration
Meeting category.
+Description
+string
Description of meeting.
+Active
+bool
Active status of meeting.
+MeetingStart
+DateTime
Start of meeting.
+MeetingEnd
+DateTime
End of meeting.
+VisibilityStart
+DateTime
Start of visibility period.
+VisibilityEnd
+DateTime
End of visibility period.
+Participants
+List of PartyItem named Party
Meeting participants.
+Stakeholders
+List of PartyItem named Party
Meeting stakeholders.
+SecurityGroups
+List of PartyGroupItem named PartyGroup
The security groups, users or organizations that are part of the access
restrictions for the meeting. The parties are accessed by their name when
patching and creating meetings.
+Link
+List of Link
One or more links to other related resources.
+The XML root element is <Meeting> .
+178
+
+Meeting example
+<Meeting xmlns="http://cbrain.com/casefile/schema/">
<Id>386596</Id>
<MeetingNumber>2013 - 45</MeetingNumber>
<Title>My meeting</Title>
<Category>
<Title>Kultur- og Fritidsudvalget</Title>
<Code>KUFR</Code>
</Category>
<Description>Blah blah blah ...</Description>
<Active>true</Active>
<MeetingStart>2013-02-20T15:00:00</MeetingStart>
<MeetingEnd>2013-02-20T16:00:00</MeetingEnd>
<VisibilityStart>2013-02-20T00:00:00</VisibilityStart>
<VisibilityEnd>2013-03-22T00:00:00</VisibilityEnd>
<Participants>
<Party>
<Name>Karin Ingemann Petersen</Name>
<EMail />
<Link href="..."
rel="self"
type="application/vnd.cbrain.casefile+xml"
title="Self" />
</Party>
</Participants>
<Stakeholders>
<Party>
<Name>Brian Ipsum Hansen</Name>
<EMail />
<Link href="..."
rel="self"
type="application/vnd.cbrain.casefile+xml"
title="Self" />
</Party>
</Stakeholders>
<Link href="..."
rel="self"
type="application/vnd.cbrain.casefile+xml"
title="My meetings" />
<Link href="..."
rel="http://cbrain.com/casefile/rel/related-case"
type="application/vnd.cbrain.casefile+xml"
title="Related case" />
</Meeting>
+Create new meeting
+A meeting may be created using the Post Once Exactly pattern (see Data manipulation). Follow the
link named http://cbrain.com/casefile/rel/create-meeting from the service index to locate the POE
resource for creating a meeting.
+179
+
+Table 117. Input parameters for creating a meeting
+Name
+Description
+Title
+string (255 characters)
Meeting title.
+Category
+string
Meeting category reference (external ID or abbreveation of enumeration item).
+Description
+string
Description of meeting.
+Active
+bool
Active status of meeting.
+MeetingStart
+DateTime
Start of meeting.
+MeetingEnd
+DateTime
End of meeting.
+VisibilityStart
+DateTime
Start of visibility period.
+VisibilityEnd
+DateTime
End of visibility period.
+Participants
+List of PartyReference
Meeting participants.
+Stakeholders
+List of PartyReference
Meeting stakeholders.
+SecurityGroups
+List of PartyGroupItem named PartyGroup
The list of security groups, users or organizations to include in the access
restrictions of the new meeting. The security groups are referenced by the name
shown in the F2 desktop client.
+KeywordCode
+string (read-only)
The code that represents a keyword to be associated with the new meeting. This
can either be in the format of ##.##.## when used with keywords from
"Kommunernes Landsforening" — or the complete path to a specific keyword
name (as seen from the desktop client) or the external ID of the keyword. As the
complete paths and external ID’s may overlap, the external ID takes precedence.
+KeywordCodes
+List of string (read-only)
A list of keyword codes. Each keyword code is handled in the same way as the
above singular KeywordCode .
+180
+
+Example request for creating a meeting (include first POE step)
+POST /meeting-create-url HTTP/1.1
Content-Length: 0
+> HTTP/1.1 201 Created
> Location: /meeting-create-poc-url
> Content-Length: 0
+POST /meeting-create-poc-url HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 1292
+Title=A+new+meeting&
Category=TEKM&
Active=true&
Description=Description+related+to+the+new+meeting&
MeetingStart=2013-01-03T16%3a36%3a00&
MeetingEnd=2013-01-03T19%3a36%3a00&
VisibilityStart=2012-12-04T16%3a36%3a00&
VisibilityEnd=2013-02-02T16%3a36%3a00&
Participants%3a0.PartyNo=2000001001&
Participants%3a0.OrganizationNo=2000000001&
Stakeholders%3a0.Login=Sagsbehandler24&
Stakeholders%3a0.PickFirstMatch=false&
SecurityGroups%3a0.Name=SG4&
SecurityGroups%3a1.Name=SG5&
KeywordCode=00.07.00&
DeletionActionCode=B&
ProcessInstructionCode=G10
+Modify meeting
+A meeting may be modified by issuing an HTTP PATCH request targeted at the meeting resource
URL.
+The simple properties are straight forward to replace with similar typed values, but some of the
complex meeting properties need special encoding when patching. These properties are:
+Table 118. Properties needing special encoding when patching
+Name
+Description
+Participants
+Use an array of PartyReference objects to reference the required parties.
+Stakeholders
+Use an array of PartyReference objects to reference the required parties.
+SecurityGroups
+Use an array of PartyGroupReference objects to reference the required parties.
+Expected link relations
+self
+http://cbrain.com/casefile/rel/related-case
+Link to "shadow case" for the meeting.
+181
+
+Submission event log
+Details about submissions from F2’s self-service application can be stored as submission event log
entries in the database. This is primarily for internal use and as such there is no way to read
existing log entries via F2-REST.
+Create submission event log entry
+Follow the link relation http://cbrain.com/casefile/rel/create-submission-event-log from the service
index to find a resource for creating submission event log entries. Then issue an HTTP POST
request to it with the following parameters
+Table 119. Input parameters for creating submission event log entry
+Name
+Description
+IpAddress
+string
The IP-address of the device making the submission.
+UserAgent
+string
The user’s user agent provided by the user’s browser.
+Identity
+string
The identity of the user making the submission.
+SubmissionKey
+string
The ID of the submission.
+UrlReferrer
+string
The URL from which the user made the submission.
+Configuration
+Client configuration
+Each client accessing F2-REST needs to be registered first. This is done by adding a <Client> entry
to the file ClientValidationRules.config.
+Registering a client means we assign a Client ID and Client Secret for the client, which allows it to
access F2-REST, and then configure which features of F2-REST the client is allowed to use.
+A typical <Client> entry for F2-REST may look something like this:
+182
+
+<?xml version="1.0" encoding="utf-8" ?>
<Clients xmlns="http://cbrain.com/oauth2/clientvalidation/schema">
<Client>
<!-- Client ID (choose one) -->
<Id>ThirdPartyIntegrator</Id>
<!-- Client secret (generate a secure random secret string) -->
<Secret>968hjads01xzfwjrh74aafd3lsufpr</Secret>
<!-- Client description (for internal book keeping) -->
<Description>Client for blah blah ...</Description>
<!-- OAuth2 specific: client ID in payload-body or header -->
<AllowClientIdInBody>false</AllowClientIdInBody>
<!-- Require F2 user password when authenticating (often false) -->
<RequireUserPassword>false</RequireUserPassword>
<!-- List of users this client is allowed to authenticate as -->
<Users>
<!-- User name -->
<User>Lise Nielsen</User>
</Users>
<!-- Allow client to authenticate as all possible F2 users -->
<AllowAllUsers>false</AllowAllUsers>
<!-- Allow authentication using authorization code from Windows AD SSO -->
<AllowAuthorizationCode>false</AllowAuthorizationCode>
<!-- Allowed redirect URLs for Windows AD Single Sign On -->
<RedirectUrls>
<Url>...some URL to client callback resource ...</Url>
</RedirectUrls>
<!-- Enable login with F2 session identifier (used by desktop clients) -->
<AllowF2SessionId>false</AllowF2SessionId>
</Client>
</Clients>
+See the separate configuration file format manual “Client validation rules – configuration files” for
further information.
+Authenticating with Windows AD
+F2-REST can be configured to authenticate users against Windows AD (similar to the F2-Desktop
Client), such that a third-party service may operate on behalf on any known domain user. The
actual flow is described in the normal F2-REST manual.
+To enable authentication using Windows AD, the following must be configured in F2-REST
Web.config:
+1. Activate use of F2-AuthenticateService by setting OAuth2.UseAuthenticationServer to true.
+2. Make sure OAuth2.AuthenticationServerUrl refers to F2-AuthenticateService’s authorization
+URL (which is <f2auth-root>/oauth2/authorize where <f2auth-root> is the root directory of F2-
AuthenticateService). If available, this should be the F2-AuthenticateService configured for
single sign on.
+3. Make sure AuthenticationServerUrl refers to the web interface of F2-AuthenticateService
+(which is <f2auth-root>/F2AuthenticateService.asmx). If available, this should be the F2-
AuthenticateService configured for anonymous access.
+4. Make sure RequiredDomain is set to the correct AD domain.
+183
+
+5. Make sure the configuration file ClientValidationRules.config is identical on both the F2-REST
+server and the F2-AuthenticateService.
+OpenID Connect with AD Single Sign On
+F2-REST also supports OpenID Connect (OIDC, see http://openid.net/connect/) which allows clients
to verify the identity of the end-user based on the authentication performed by an external
authorization server, as well as to obtain basic profile information about the end-user in an
interoperable and REST-like manner.
+Setting up OIDC requires one more OAuth2 setting in the web.config file:
+1. Make sure OAuth2.OpenIDTokenServiceUrl refers to F2-AuthenticateService’s token service
+URL (which is <f2auth-root>/oauth2/tokenservice where <f2auth-root> is the root directory of
F2-AuthenticateService).
+Please note that F2-REST does not function as an Identity Provider in itself, but delegates the
operation to F2-AuthenticateService.
+Browser login
+F2-REST allows developers to browse through the REST API using a standard web-browser.
+The default mechanism for logging in using the browser is "HTTP Basic Authentication" where the
browser itself asks the end-user for his/her credentials and then transfer those credentials in an
HTTP header for F2-REST to verify.
+It is although also possible to use federated login with OpenID Connect, where F2-REST redirects
the browser to some external identity provider where the end-user authenticates. This allows the
end-user, typically a developer, to authenticate using for instance Windows AD (through cBrain’s
IdentityHub) or other OIDC compliant identity providers.
+Federated login using OpenID Connect must be configured as described in the next section.
+Federated login with OpenID Connect
+In order to use OpenID Connect for federated login in to F2-REST, it is necessary to configure the
identity provider in the file IdentityProviders.config found in the root of the F2-REST installation
directory.
+Once
+the
+identity
+provider
+configuration
+is
+done
+and
+the
+application
+setting
+OAuth2.DefaultExternalIdentityProvider is added to web.config and references the right
+identity provider, the service index page at <F2-rest-root>/serviceindex adds “Login”-link at the
top, allowing the end-user to login through a browser.
+The identity provider configuration is also used when a client tries to authenticate with a JWT
identity token it has received from an external identity provider.
+184
+
+Rate Limiting
+It is possible to enable Rate Limiting in F2-REST. A Rate Limit is the number of API calls an app or
user can make within a given time period. If this limit is exceeded the app or user may be
throttled. In F2-REST requests can be limited for individual Client IDs.
+Rate Limiting is enabled by adding a Rate Limit rule section to the F2-REST web.config file:
+<RateLimit>
<rules>
<rule entry="CientId1" limitPerMinute="5000" limitPerSecond="100" />
<rule entry="CientId2" limitPerHour="50000" />
</rules> +
</RateLimit>
+Each rule should have an "entry" attribute containing the Client ID for which the rule applies. If the
value is "*"" the rule will be applied to all Client IDs individually, i.e. it corresponds to adding the
same rule for each Client ID. If no "entry" attribute is specified the rule is ignored.
+Each rule can have one or more limit attributes: "limitPerSecond", "limitPerMinute", "limitPerHour",
"limitPerDay" and "limitPerWeek". The value of these indicate the number of requests allowed
within the time period.
+If a request is received that violates a rate limit rule, F2-REST will deny the request and return a
response with status code 429 ("Too Many Requests").
+Note that request history is not persisted, so restarting F2-REST will result in a reset of rate
limiting.
+185
+
+Virus scanning of uploaded documents
+F2-REST is able to scan every document received and replace it with a warning document, should
the document contain a virus.
+Please see the "F2 Security Server installation manual" for details about installing virus scanning.
+The F2 Security Server itself is not required for virus scan of documents in F2-REST, so that part
can be ignored - it is only the core virus scanning service that needs to be accessible.
+When the virus scanning service is up and running, you should change the following app-settings
in the F2-REST web.config file:
+Setting
+Description
+AntiVirus.VirusFoundTemplate
+The path to the warning template file, which should
replace an uploaded file, should it contain a virus. The
file must be a Word-file.
+A default template is already included as a part of the
installation. This template can be found in the root of
the F2-REST-folder.
+If you remove the '_' in the start of the filename, the
default of this app-setting will match the file.
+The file can contain the following merge-fields:
+$definitionFileVersion$
+$threatName$
+$scannerIdentifier$
+$md5$
+$fileExtension$
+AntiVirus.UseAntiVirusInRest
+A Boolean setting. If true, every document will be
scanned. If true and the anti-virus service is not running,
then F2-REST will return an HTTP error code 500.
+AntiVirus.Engine
+Name of a DLL containing the virus-scanning engine to be
used.
+Currently
+the
+only
+supported
+virus-scanning
+engine
+DLL
+is
+"CBrain.AntiVirus.ClamAV.ClamAVScanner,CBrain.AntiVirus.ClamAV".
+186
+
+Bibliography
+[Fielding] Fielding, Roy Thomas. Architectural Styles and the Design of Network-based Software
Architectures. Irvine, California : University of California, Irvine, 2000.
+[OIDC] OpenID Connect. OpenID. [Online] http://openid.net/connect/.
+[OpenSearch]
+OpenSearch
+specification
+1.1.
+OpenSearch.org.
+[Online]
+http://www.opensearch.org/Specifications/OpenSearch/1.1.
+[JSONPatch] RFC 6902 - JavaScript Object Notation (JSON) Patch. IETF. [Online] 2013.
https://tools.ietf.org/html/rfc6902. RFC 6902.
+[ATOM]
+RFC
+4287
+-
+The
+Atom
+Syndication
+Format.
+IETF.
+[Online]
+2005.
+http://tools.ietf.org/html/rfc4287. RFC 4287.
+[JSON] RFC 4627 - The application/json Media Type for JavaScript Object Notation (JSON). IETF.
[Online] 2006. http://tools.ietf.org/html/rfc4627. RFC 4627.
+[MultipartFormdata] RFC 2388 - Returning Values from Forms: multipart/form-data. IETF. [Online]
1998. http://www.ietf.org/rfc/rfc2388.txt. RFC 2388.
+[OAuth] RFC 6749 - The OAuth 2.0 Authorization Framework. IETF. [Online] 2012.
https://tools.ietf.org/html/rfc6749. RFC 6749.
+[XSD] W3C XML Schema Definition Language (XSD) 1.1 Part 2: Datatypes. W3C. [Online] 2012.
http://www.w3.org/TR/2012/REC-xmlschema11-2-20120405/.
+[DATETIME] RFC 3339 - Date and Time on the Internet: Timestamps. IETF. [Online] 2002.
http://tools.ietf.org/html/rfc3339. RFC 3339.
+[CSV] RFC 4180 - Common Format and MIME Type for Comma-Separated Values (CSV) Files.
IETF. [Online] October 2005. http://tools.ietf.org/html/rfc4180. RFC 4180.
+[JWT] RFC 7519 - JSON Web Token (JWT). IETF. [Online] 2015. https://tools.ietf.org/html/rfc7519.
+[OAuthTokenInspection] RFC 7662 - OAuth 2.0 Token Introspection. IETF. [Online] 2015.
https://tools.ietf.org/html/rfc7662
+[XMLTypes] W3C XML Schema Definition Language (XSD) 1.1 Part 2: Datatypes [Online 2012]
https://www.w3.org/TR/xmlschema11-2/.
+[XMLSchema] W3C XML Schema Definition Language (XSD) 1.1 Part 1: Structures [Online] 2012.
https://www.w3.org/TR/xmlschema11-1/.
+187
+
+Document Outline
+
+
+
+
diff --git a/src/Client/ApiClient.php b/src/Client/ApiClient.php
new file mode 100644
index 0000000..6bab36d
--- /dev/null
+++ b/src/Client/ApiClient.php
@@ -0,0 +1,261 @@
+configureOptions($resolver);
+
+ $this->options = $resolver->resolve($options);
+ }
+
+ /**
+ * @return array
+ *
+ * @throws \Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface
+ * @throws \Symfony\Contracts\HttpClient\Exception\DecodingExceptionInterface
+ * @throws \Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface
+ * @throws \Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface
+ * @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface
+ */
+ public function getServiceIndex(): array
+ {
+ $path = '/F2Rest/ServiceIndex';
+ $response = $this->client()->request(Request::METHOD_GET, $path, [
+ 'headers' => [
+ 'Accept' => 'application/json',
+ ],
+ ]);
+
+ return $response->toArray();
+ }
+
+ /**
+ * @param array{q: string, count: int} $query
+ * @return Atom[]
+ *
+ * @throws \Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface
+ * @throws \Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface
+ * @throws \Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface
+ * @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface
+ */
+ public function caseSearch(string $q, int $count = 10): array
+ {
+ $query = [
+ 'q' => $q,
+ 'count' => $count,
+ ];
+ $path = '/F2Rest/search/cases';
+ // @todo /F2Rest/ServiceIndex.json reports
+ //
+ // "http://cbrain.com/casefile/rel/case-search": {
+ // "href": "/F2Rest/search/cases",
+ // "title": "Case file search"
+ // },
+ //
+ // which refers to the actual search URL: /F2Rest/searches/cases
+ $path = '/F2Rest/searches/cases';
+ // $path = $this->getRequestUrl('http://cbrain.com/casefile/rel/case-search');
+ $response = $this->request(Request::METHOD_GET, $path, [
+ 'query' => $query,
+ ]);
+
+ $items = [];
+ $sxe = new \SimpleXMLElement($response->getContent());
+ foreach ($sxe->entry as $entry) {
+ $items[] = Atom::fromSimpleXMLElement($entry);
+ }
+
+ return $items;
+ }
+
+ public function caseById(string $id): CaseFile
+ {
+ $url = $this->getRequestUrl('http://cbrain.com/casefile/rel/case-by-id', [
+ 'id' => $id,
+ ]);
+ $response = $this->request(Request::METHOD_GET, $url);
+
+ if (Response::HTTP_OK !== $response->getStatusCode()) {
+ throw new ApiException($response);
+ }
+
+ return CaseFile::fromSimpleXMLElement(new \SimpleXMLElement($response->getContent()));
+ }
+
+ public function matterSearch(string $searchTerms, int $count = 10): array
+ {
+ $query = [
+ 'searchTerms' => $searchTerms,
+ 'count' => $count,
+ ];
+ // @todo /F2Rest/ServiceIndex.json reports
+ //
+ // "http://cbrain.com/casefile/rel/case-search": {
+ // "href": "/F2Rest/search/cases",
+ // "title": "Case file search"
+ // },
+ //
+ // which refers to the actual search URL: /F2Rest/searches/cases
+ $url = '/F2Rest/searches/matters';
+ $url = '/F2Rest/searches/matters?q={searchTerms}&count={count}';
+ $url = $this->replacePlaceholders($url, $query);
+// $url = $this->getRequestUrl('http://cbrain.com/casefile/rel/matter-search', [
+// ]);
+ $response = $this->request(Request::METHOD_GET, $url, [
+ 'query' => $query,
+ ]);
+
+ $items = [];
+ $sxe = new \SimpleXMLElement($response->getContent());
+ foreach ($sxe->entry as $entry) {
+ $items[] = Atom::fromSimpleXMLElement($entry);
+ }
+
+ return $items;
+ }
+
+ public function matterById(string $id): Matter
+ {
+ $url = $this->getRequestUrl('http://cbrain.com/casefile/rel/matter-by-id', [
+ 'id' => $id,
+ ]);
+ $response = $this->request(Request::METHOD_GET, $url);
+
+ if (Response::HTTP_OK !== $response->getStatusCode()) {
+ throw new ApiException($response);
+ }
+
+ return Matter::fromSimpleXMLElement(new \SimpleXMLElement($response->getContent()));
+ }
+
+ public function matterByMatterNumber(string $matterNumber): Matter
+ {
+ $url = $this->getRequestUrl('http://cbrain.com/casefile/rel/matter-by-matter-number', [
+ 'matterNumber' => $matterNumber,
+ ]);
+ $response = $this->request(Request::METHOD_GET, $url);
+
+ if (Response::HTTP_OK !== $response->getStatusCode()) {
+ throw new ApiException($response);
+ }
+
+ return Matter::fromSimpleXMLElement(new \SimpleXMLElement($response->getContent()));
+ }
+
+
+ /**
+ * @return array{access_token: string, token_type: string}
+ */
+ protected function getAccessToken(): array
+ {
+ // @todo Check existing access token is not expired.
+
+ $client = $this->client();
+ $response = $client->request(Request::METHOD_POST, '/F2Rest/oauth2/token', [
+ 'auth_basic' => [
+ $this->options['api_username'],
+ $this->options['api_secret'],
+ ],
+ 'headers' => [
+ 'accept' => 'application/json',
+ ],
+ 'body' => [
+ 'grant_type' => 'password',
+ 'username' => $this->options['f2_username'],
+ ],
+ ]);
+
+ /** @var array{access_token: string, token_type: string} $token */
+ $token = $response->toArray();
+
+ // @todo Store access token.
+
+ return $token;
+ }
+
+ protected function request(string $method, string $path, array $options = []): ResponseInterface
+ {
+ $accessToken = $this->getAccessToken();
+
+ return $this->client()->request(
+ $method,
+ $path,
+ $options
+ + [
+ 'auth_bearer' => $accessToken['access_token'],
+ ],
+ );
+ }
+
+ protected function client(): HttpClientInterface
+ {
+ if (null === $this->client) {
+ $this->client = HttpClient::create([
+ 'base_uri' => $this->options['api_uri'],
+ ]);
+ }
+
+ return $this->client;
+ }
+
+ protected function configureOptions(OptionsResolver $resolver): void
+ {
+ $resolver->setRequired([
+ 'api_uri',
+ 'api_username',
+ 'api_secret',
+ 'f2_username',
+ ]);
+ }
+
+ protected function getRequestUrl(string $rel, array $values): string
+ {
+ // @todo Cache this!
+ $index = $this->getServiceIndex();
+
+ $url = $index[$rel]['href'] ?? null;
+ if (null === $url) {
+ throw new RuntimeException(sprintf('Cannot get rel %s', $rel));
+ }
+
+ return $this->replacePlaceholders($url, $values);
+ }
+
+ protected function replacePlaceholders(string $url, array $values): string
+ {
+ // Replace URL placeholders ('{…}')
+ return preg_replace_callback(
+ '/{(?P[^}]+)}/',
+ static function (array $matches) use ($url, $values): string {
+ $name = $matches['name'];
+ if (!array_key_exists($name, $values)) {
+ throw new RuntimeException(sprintf('Missing value %s for URL %s', $name, $url));
+ }
+
+ return rawurlencode((string)$values[$name]);
+ },
+ $url,
+ );
+ }
+}
diff --git a/src/Command/F2ApiClientCommand.php b/src/Command/F2ApiClientCommand.php
new file mode 100644
index 0000000..f7471f8
--- /dev/null
+++ b/src/Command/F2ApiClientCommand.php
@@ -0,0 +1,70 @@
+createClient();
+
+ $getArray = static function (?string $value): array {
+ if (null === $value) {
+ throw new InvalidArgumentException('Missing JSON argument');
+ }
+ try {
+ $array = json_decode($value, true, 512, JSON_THROW_ON_ERROR);
+ } catch (\JsonException $e) {
+ throw new InvalidArgumentException(sprintf('Invalid JSON: %s', $e->getMessage()));
+ }
+
+ return $array;
+ };
+
+ $response = match ($action) {
+ 'getServiceIndex' => $client->getServiceIndex(),
+ 'caseSearch' => $client->caseSearch($arg),
+ 'caseById' => $client->caseById($arg),
+ 'matterSearch' => $client->matterSearch($arg),
+ 'matterById' => $client->matterById($arg),
+ 'matterByMatterNumber' => $client->matterByMatterNumber($arg),
+ default => throw new InvalidArgumentException(sprintf('Invalid action: %s', $action)),
+ };
+
+ $io->writeln((string) json_encode($response, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE));
+
+ return Command::SUCCESS;
+ }
+
+ private function createClient(): ApiClient
+ {
+ $getEnv = static function (string $name): string {
+ $value = getenv($name);
+ if (false === $value || '' === trim($value)) {
+ throw new RuntimeException(sprintf('Cannot read environment variable %s', $name));
+ }
+
+ return $value;
+ };
+
+ $config = [
+ 'api_uri' => $getEnv('F2_API_URI'),
+ 'api_username' => $getEnv('F2_API_USERNAME'),
+ 'api_secret' => $getEnv('F2_API_SECRET'),
+ 'f2_username' => $getEnv('F2_F2_USERNAME'),
+ ];
+
+ return new ApiClient($config);
+ }
+}
diff --git a/src/Exception/ApiException.php b/src/Exception/ApiException.php
new file mode 100644
index 0000000..1c0efe9
--- /dev/null
+++ b/src/Exception/ApiException.php
@@ -0,0 +1,39 @@
+response->getStatusCode();
+ try {
+ $sxe = new \SimpleXMLElement($response->getContent(throw: false));
+ $message = (string) $sxe->Message;
+ } catch (\Throwable $t) {
+ $previous = $t;
+ }
+ parent::__construct($message, $code, $previous);
+ }
+}
diff --git a/src/Exception/Exception.php b/src/Exception/Exception.php
new file mode 100644
index 0000000..ad39c79
--- /dev/null
+++ b/src/Exception/Exception.php
@@ -0,0 +1,9 @@
+id,
+ title: (string)$sxe->title,
+ published: new \DateTimeImmutable((string)$sxe->published),
+ updated: new \DateTimeImmutable((string)$sxe->updated),
+ );
+ }
+
+ public function __toString(): string
+ {
+ return sprintf('%s (%s)', $this->title, $this->id);
+ }
+
+ public function jsonSerialize(): array
+ {
+ return [
+ 'id' => $this->id,
+ 'title' => $this->title,
+ 'published' => $this->published->format(\DateTimeInterface::ATOM),
+ 'updated' => $this->updated->format(\DateTimeInterface::ATOM),
+ ];
+ }
+}
diff --git a/src/Model/CaseFile.php b/src/Model/CaseFile.php
new file mode 100644
index 0000000..b92f72e
--- /dev/null
+++ b/src/Model/CaseFile.php
@@ -0,0 +1,92 @@
+Id,
+ caseNumber: (string) $sxe->CaseNumber,
+ title: (string) $sxe->Title,
+ createdDate: new \DateTimeImmutable((string) $sxe->CreatedDate),
+ modifiedDate: new \DateTimeImmutable((string) $sxe->ModifiedDate),
+ modifiedBy: PartyItem::fromSimpleXMLElement($sxe->ModifiedBy),
+ responsible: PartyItem::fromSimpleXMLElement($sxe->Responsible),
+ // matters: static::listOf(Matter::class, $sxe->Matters),
+ );
+ }
+
+ public function __toString()
+ {
+ return sprintf('Case %s: %s', $this->caseNumber, $this->title);
+ }
+
+ public function jsonSerialize(): array
+ {
+ return [
+ 'id' => $this->id,
+ 'caseNumber' => $this->caseNumber,
+ 'title' => $this->title,
+ 'createdDate' => $this->createdDate,
+ 'modifiedDate' => $this->modifiedDate,
+ 'modifiedBy' => $this->modifiedBy->jsonSerialize(),
+ 'responsible' => $this->responsible->jsonSerialize(),
+ // 'matters' => array_map(static fn (Matter $matter) => $matter->jsonSerialize(), $this->matters),
+ ];
+ }
+}
diff --git a/src/Model/Document.php b/src/Model/Document.php
new file mode 100644
index 0000000..af9f6e0
--- /dev/null
+++ b/src/Model/Document.php
@@ -0,0 +1,22 @@
+matter;
+ }
+
+ public function setMatter(Matter $matter): Document
+ {
+ $this->matter = $matter;
+
+ return $this;
+ }
+}
diff --git a/src/Model/Matter.php b/src/Model/Matter.php
new file mode 100644
index 0000000..e58b5fa
--- /dev/null
+++ b/src/Model/Matter.php
@@ -0,0 +1,53 @@
+Id,
+ matterNumber: (string)$sxe->MatterNumber,
+ title: (string) $sxe->Title,
+ createdDate: new \DateTimeImmutable((string) $sxe->CreatedDate),
+ modifiedDate: new \DateTimeImmutable((string) $sxe->ModifiedDate),
+ modifiedBy: PartyItem::fromSimpleXMLElement($sxe->ModifiedBy),
+ responsible: PartyItem::fromSimpleXMLElement($sxe->Responsible),
+ );
+ }
+
+ public function __toString()
+ {
+ return sprintf('Matter %s: %s', $this->matterNumber, $this->matterNumber);
+ }
+
+ public function jsonSerialize(): array
+ {
+ return [
+ 'id' => $this->id,
+ 'matterNumber' => $this->matterNumber,
+ 'title' => $this->title,
+ 'createdDate' => $this->createdDate,
+ 'modifiedDate' => $this->modifiedDate,
+ 'modifiedBy' => $this->modifiedBy->jsonSerialize(),
+ 'responsible' => $this->responsible->jsonSerialize(),
+ ];
+ }
+}
diff --git a/src/Model/PartyItem.php b/src/Model/PartyItem.php
new file mode 100644
index 0000000..910f4e3
--- /dev/null
+++ b/src/Model/PartyItem.php
@@ -0,0 +1,82 @@
+Name,
+ email: (string) $sxe->Email,
+ type: (string) $sxe->Type,
+ id: (int) $sxe->Id,
+ partyNumber: (int) $sxe->PartyNumber,
+ );
+ }
+
+ public function __toString()
+ {
+ return sprintf('Party: %s (%s)', $this->name, $this->type);
+ }
+
+ public function jsonSerialize(): array
+ {
+ return [
+ 'name' => $this->name,
+ 'email' => $this->email,
+ 'type' => $this->type,
+ 'id' => $this->id,
+ 'partyNumber' => $this->partyNumber,
+ ];
+ }
+}