diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 1e2710087b58717b09b70fc06c2caf5bd4145ed2..440e166a2aa5843f06d06b27f243250762ad0710 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,3 +1,9 @@
+include:
+- project: 'eclipse/xfsc/dev-ops/ci-templates'  
+  file: 'helm-build-ci.yaml'  
+  ref: main
+
+
 variables:
   DOCKERFILE: Dockerfile
   TAG: ${HARBOR_HOST}/${HARBOR_PROJECT}/$SERVICE
diff --git a/apps/did-manager/LICENSE b/apps/did-manager/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..6bc596c6d9ae158f03739f543ee9d26c4fb5e8d6
--- /dev/null
+++ b/apps/did-manager/LICENSE
@@ -0,0 +1,636 @@
+GAIA-X "Attestation Manager" 
+
+is the microservice which is responsible for handling the features 
+related to issuance of credentials of the GAIA-X project. It handles REST 
+endpoints for Schemas, Credential Definitions and Verifiable Credentials.
+
+Copyright 2022 Vereign AG
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+
+This Attestation Manager incorporates 
+
+"elastic/ecs-winston-format", 
+
+a Node.js package to provide a formatter for the winston logger compatible 
+with Elastic Common Schema (ECS) logging, which is covered by the following copyright
+and permission notice:
+
+Copyright 2020 Elastic and contributors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+
+This Attestation Manager also incorporates
+
+"nestjs", 
+
+a progressive Node.js framework for building efficient and scalable server-side applications, 
+which is covered by the following copyright and permission notice:
+
+Copyright (c) 2017-2022 Kamil Mysliwiec <https://kamilmysliwiec.com>
+
+(The MIT License)
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+'Software'), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+
+This Attestation Manager also incorporates 
+
+"nestjs/terminus"
+
+, integrated healthchecks for Nest, which contains the
+following copyright and permission notice:  
+
+Copyright (c) 2018-2021 Livio Brunner, Kamil Myśliwiec
+
+(The MIT License)
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+'Software'), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+
+This Attestation Manager also incorporates
+
+"prisma client"
+
+,an auto-generated query builder that enables type-safe database access and reduces 
+boilerplate, which is covered by the following copyright and permission notice:
+
+Copyright 2019 Johannes Schickling
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+
+This Attestation Manager also incorporates 
+
+"types/node"
+
+,type definitions for Node, which is covered by the following copyright and
+permission notice: 
+
+Copyright Microsoft TypeScript, DefinitelyTyped, Alberto Schiabel, 
+Alvis HT Tang, Andrew Makarov, Benjamin Toueg, Chigozirim C., David Junger, Deividas Bakanas, Eugene Y. Q. Shen, 
+Hannes Magnusson, Huw, Kelvin Jin, Klaus Meinhardt, Lishude, Mariusz Wiktorczyk, Mohsen Azimi, Nicolas Even, 
+Nikita Galkin, Parambir Singh, Sebastian Silbermann, Simon Schick, Thomas den Hollander, Wilco Bakker, wwwy3y3, 
+Samuel Ainsworth, Kyle Uehlein, Thanik Bhongbhibhat, Marcin Kopacz, Trivikram Kamat, Junxiao Shi, Ilia Baryshnikov, 
+ExE Boss, Piotr Błażejewicz, Anna Henningsen, Victor Perin, Yongsheng Zhang, NodeJS Contributors, 
+Linus Unnebäck, wafuwafu13, and Matteo Collina. 
+
+(The MIT License)
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+'Software'), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 
+
+
+This Attestation Manager also incorporates
+
+"types/express"
+
+,type definitions for Express (http://expressjs.com), which is covered by the following 
+copyright and permission notice: 
+
+Copyright Boris Yankov, China Medical University Hospital, Puneet Arora, and Dylan Frankland.
+
+(The MIT License)
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+'Software'), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 
+
+
+This Attestation Manager also incorporates 
+
+"types/jest"
+
+type definitions for Jest, which is covered by the following copyright and permission notice: 
+
+Copyright Asana (https://asana.com)// Ivo Stratev, jwbay, Alexey Svetliakov, Alex Jover Morales, Allan Lukwago, 
+Ika, Waseem Dahman, Jamie Mason, Douglas Duteil, Ahn, Jeff Lau, Andrew Makarov, Martin Hochel, Sebastian Sebald, 
+Andy, Antoine Brault, Gregor Stamać, ExE Boss, Alex Bolenok, Mario Beltrán Alarcón, Tony Hallett, Jason Yu, Pawel Fajfer, 
+Regev Brody, Alexandre Germain, and Adam Jones.
+
+(The MIT License)
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+'Software'), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+
+This Attestation Manager also incorporates 
+
+"class-validator"
+
+, a tool to allow decorator and non-decorator based validation,
+
+and
+
+"class-transformer" 
+
+,a tool to transform plain object to some instance of class and versa, also to serialize / 
+deserialize object based on criteria, both of which are covered by the following copyright 
+and permission notice:
+
+Copyright 2015-2020 TypeStack
+
+(The MIT License)
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+'Software'), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+
+This Attestation Manager also incorporates 
+
+"express"
+
+,a fast, unopinionated, minimalist web framework for node, which is covered by the following copyright
+and permission notice:
+
+Copyright (c) 2009-2014 TJ Holowaychuk <tj@vision-media.ca>
+Copyright (c) 2013-2014 Roman Shtylman <shtylman+expressjs@gmail.com>
+Copyright (c) 2014-2015 Douglas Christopher Wilson <doug@somethingdoug.com>
+
+(The MIT License)
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+'Software'), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+
+This Attestation Manager also incorporates
+
+"husky"
+
+, modern native Git hooks made easy, which is covered by the following copyright and 
+permission notice:
+
+Copyright (c) 2021 typicode
+
+(The MIT License)
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE. 
+
+
+This Attestation Manager also incorporates
+
+"joi"
+
+, the most powerful schema description language and data validator for JavaScript, which is 
+covered by the following copyright and permission notice:
+
+Copyright (c) 2012-2020, Sideway. Inc, and project contributors.
+Copyright (c) 2012-2014, Walmart.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+- Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or 
+other materials provided with the distribution.
+- The names of any contributors may not be used to endorse or promote products derived from this software without 
+specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+This Attestation Manager also incorporates
+
+"liquibase"
+
+, liquibase is an open-source database-independent library for tracking, managing and applying database schema change, which is covered
+by the following copyright and permission notice: 
+
+Copyright (c) Taylor Buckner <taylora.buckner@gmail.com>
+
+(The MIT License) 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+
+This Attestation Manager also incorporates  
+
+"moment"
+
+, a JavaScript date library for parsing, validating, manipulating, and formatting dates,
+which is covered by the following copyright and permission notice: 
+
+Copyright (c) JS Foundation and other contributors
+
+(The MIT License)
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+
+This Attestation Manager also incorporates 
+
+"nats"
+
+, a Node.js client for the NATS messaging system, which is covered by 
+the following copyright and permission notice:
+
+Copyright 2013-2018 The NATS Authors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+
+This Attestation Manager also incorporates 
+
+"pg - node postgres"
+
+, non-blocking PostgreSQL client for Node.js, which is covered by 
+the following copyright and permission notice:
+
+Copyright (c) 2010-2020 Brian Carlson (brian.m.carlson@gmail.com)
+
+(The MIT License) 
+Permission is hereby granted, free of charge, to any person obtaining a copy of 
+this software and associated documentation files (the "Software"), to deal in the 
+Software without restriction, including without limitation the rights to use, copy, 
+modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, 
+and to permit persons to whom the Software is furnished to do so, subject to the 
+following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies 
+or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 
+INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+
+This Attestation Manager also incorporates
+
+"prisma"
+
+, next-generation ORM for Node.js & TypeScript | PostgreSQL, MySQL, MariaDB, SQL Server, 
+SQLite, MongoDB and CockroachDB, which is covered by the following copyright and 
+permission notice:
+
+Copyright 2019 Johannes Schickling
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+
+This Attestation Manager also incorporates
+
+"reflect-metadata"
+
+, prototype for a Metadata Reflection API for ECMAScript, which is covered 
+by the following copyright and permission notice:
+
+Copyright 2019 Ron Buckton
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+
+This Attestation Manager also incorporates
+
+"rimraf"
+
+, a `rm -rf` util for nodejs, which is covered by the following copyright 
+and permission notice:
+
+Copyright (c) 2011-2022 Isaac Z. Schlueter and Contributors
+
+(The ISC License)
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+
+This Attestation Manager also incorporates
+
+"rxjs"
+
+, reactive extensions for JavaScript, which is covered by the following copyright 
+and permission notice:
+
+Copyright (c) 2015-2018 Google, Inc., Netflix, Inc., Microsoft Corp. and contributors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+
+This Attestation Manager also incorporates
+
+"Swagger UI Express"
+
+, allows to serve auto-generated swagger-ui generated API docs from express, 
+based on a swagger.json file, which is covered by the following copyright and 
+permission notice: 
+
+Copyright (c) 2018 Scott IT London
+
+(The MIT License) 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+
+This Attestation Manager also incorporates
+
+"winston"
+
+, a logger for just about everything, which is covered by the following copyright and
+permission notice: 
+
+Copyright (c) 2010 Charlie Robbins
+
+(The MIT License) 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+
+This Attestation Manager also incorporates
+
+"winston-elasticsearch"
+
+, an elasticsearch transport for winston, which is covered by the following copyright and
+permission notice: 
+
+Copyright (c) 2015 - 2018 Thomas Hoppe.
+Copyright (c) 2013 Jacques-Olivier D. Bernier.
+
+(The MIT License)
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/apps/did-manager/jest.config.js b/apps/did-manager/jest.config.js
new file mode 100644
index 0000000000000000000000000000000000000000..ccdd468df2bf90570fb54087fa7dea267814c888
--- /dev/null
+++ b/apps/did-manager/jest.config.js
@@ -0,0 +1,48 @@
+import { readFileSync } from 'node:fs';
+
+const swcConfig = JSON.parse(readFileSync('../../.swcrc', 'utf8'));
+
+/** @type {import('jest').Config} */
+export default {
+  moduleFileExtensions: ['js', 'ts'],
+  testEnvironment: 'node',
+  transform: {
+    '^.+\\.(js|ts)$': [
+      '@swc/jest',
+      {
+        ...swcConfig,
+        sourceMaps: false,
+        exclude: [],
+        swcrc: false,
+      },
+    ],
+  },
+  extensionsToTreatAsEsm: ['.ts'],
+  moduleNameMapper: {
+    // ESM modules require `.js` extension to be specified, but Jest doesn't work with them
+    // Removing `.js` extension from module imports
+    '^uuid$': 'uuid',
+    '^(.*)/(.*)\\.js$': '$1/$2',
+  },
+  collectCoverageFrom: ['src/**/*.(t|j)s'],
+  coverageReporters:
+    process.env.CI === 'true'
+      ? ['text-summary', 'json-summary']
+      : ['text-summary', 'html'],
+  coveragePathIgnorePatterns: [
+    '<rootDir>/node_modules/',
+    '<rootDir>/coverage/',
+    '<rootDir>/dist/',
+    '__tests__',
+    '@types',
+    '.dto.(t|j)s',
+    '.enum.ts',
+    '.interface.ts',
+    '.type.ts',
+    '.spec.ts',
+  ],
+  coverageDirectory: './coverage',
+  // With v8 coverage provider it's much faster, but
+  // with this enabled it's not possible to ignore whole files' coverage
+  coverageProvider: 'v8',
+};
diff --git a/apps/did-manager/nest-cli.json b/apps/did-manager/nest-cli.json
new file mode 100644
index 0000000000000000000000000000000000000000..b9af737f405bfea055dcb58728c31d912fef06f3
--- /dev/null
+++ b/apps/did-manager/nest-cli.json
@@ -0,0 +1,14 @@
+{
+  "$schema": "https://json.schemastore.org/nest-cli",
+  "collection": "@nestjs/schematics",
+  "sourceRoot": "src",
+  "compilerOptions": {
+    "typeCheck": true,
+    "builder": {
+      "type": "swc",
+      "options": {
+        "swcrcPath": "../../.swcrc"
+      }
+    }
+  }
+}
diff --git a/apps/did-manager/package.json b/apps/did-manager/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..669db0a31c33af6771afadff248bd04fc512c268
--- /dev/null
+++ b/apps/did-manager/package.json
@@ -0,0 +1,49 @@
+{
+  "name": "@ocm/did-manager",
+  "version": "1.0.0",
+  "description": "",
+  "author": "Konstantin Tsabolov <konstantin.tsabolov@spherity.com>",
+  "contributors": [
+    "Konstantin Tsabolov <konstantin.tsabolov@spherity.com>"
+  ],
+  "private": true,
+  "license": "Apache-2.0",
+  "type": "module",
+  "scripts": {
+    "clean": "rimraf dist coverage *.tsbuildinfo",
+    "prebuild": "pnpm clean",
+    "build": "nest build -p tsconfig.production.json",
+    "start": "nest start --watch --preserveWatchOutput",
+    "test": "jest"
+  },
+  "dependencies": {
+    "@nestjs/common": "^10.3.0",
+    "@nestjs/config": "^3.1.1",
+    "@nestjs/core": "^10.3.0",
+    "@nestjs/microservices": "^10.3.0",
+    "@nestjs/platform-express": "^10.3.0",
+    "@nestjs/swagger": "^7.2.0",
+    "@ocm/shared": "workspace:*",
+    "class-transformer": "^0.5.1",
+    "class-validator": "^0.14.0",
+    "express": "^4.17.3",
+    "joi": "^17.11.0",
+    "nats": "^2.18.0",
+    "reflect-metadata": "^0.1.13",
+    "rxjs": "^7.8.1"
+  },
+  "devDependencies": {
+    "@nestjs/cli": "^10.3.0",
+    "@nestjs/schematics": "^10.1.0",
+    "@nestjs/testing": "^10.3.0",
+    "@swc/cli": "^0.1.62",
+    "@swc/core": "^1.3.96",
+    "@swc/jest": "^0.2.29",
+    "@types/express": "^4.17.21",
+    "@types/jest": "^29.5.8",
+    "@types/node": "^20.9.0",
+    "jest": "^29.7.0",
+    "rimraf": "^5.0.5",
+    "typescript": "^5.3.2"
+  }
+}
diff --git a/apps/did-manager/src/application.ts b/apps/did-manager/src/application.ts
new file mode 100644
index 0000000000000000000000000000000000000000..8e4cea804ed728210217f9abc5f24645c6de7d23
--- /dev/null
+++ b/apps/did-manager/src/application.ts
@@ -0,0 +1,78 @@
+import type { ConfigType } from '@nestjs/config';
+import type { ClientProvider } from '@nestjs/microservices';
+
+import { Module } from '@nestjs/common';
+import { ConfigModule } from '@nestjs/config';
+import { RouterModule } from '@nestjs/core';
+import { ClientsModule, Transport } from '@nestjs/microservices';
+import { HealthModule } from '@ocm/shared';
+
+import { NATS_CLIENT } from './common/constants.js';
+import { httpConfig } from './config/http.config.js';
+import { natsConfig } from './config/nats.config.js';
+import { validationSchema } from './config/validation.js';
+import { DIDsModule } from './dids/dids.module.js';
+
+@Module({
+  imports: [
+    ConfigModule.forRoot({
+      isGlobal: true,
+      load: [httpConfig, natsConfig],
+      cache: true,
+      expandVariables: true,
+      validationSchema,
+      validationOptions: {
+        allowUnknown: true,
+        abortEarly: true,
+      },
+    }),
+
+    ClientsModule.registerAsync({
+      isGlobal: true,
+      clients: [
+        {
+          name: NATS_CLIENT,
+          inject: [natsConfig.KEY],
+          useFactory: (config: ConfigType<typeof natsConfig>) => {
+            const provider: Required<ClientProvider> = {
+              transport: Transport.NATS,
+              options: {
+                servers: config.url as string,
+              },
+            };
+
+            if ('user' in config && 'password' in config) {
+              provider.options.user = config.user as string;
+              provider.options.pass = config.password as string;
+            }
+
+            return provider;
+          },
+        },
+      ],
+    }),
+
+    HealthModule.registerAsync({
+      inject: [natsConfig.KEY],
+      useFactory: (config: ConfigType<typeof natsConfig>) => {
+        const options: Parameters<typeof HealthModule.register>[0] = {};
+
+        if (config.monitoringUrl) {
+          options.nats = {
+            monitoringUrl: config.monitoringUrl as string,
+          };
+        }
+
+        return options;
+      },
+    }),
+
+    DIDsModule,
+
+    RouterModule.register([
+      { module: HealthModule, path: '/health' },
+      { module: DIDsModule, path: '/dids' },
+    ]),
+  ],
+})
+export class Application {}
diff --git a/apps/did-manager/src/common/constants.ts b/apps/did-manager/src/common/constants.ts
new file mode 100644
index 0000000000000000000000000000000000000000..476c13d6650f504d8a2509b73e7c3c03a24d3d6c
--- /dev/null
+++ b/apps/did-manager/src/common/constants.ts
@@ -0,0 +1,2 @@
+export const SERVICE_NAME = 'DID_MANAGER_SERVICE';
+export const NATS_CLIENT = Symbol('NATS_CLIENT');
diff --git a/apps/did-manager/src/config/http.config.ts b/apps/did-manager/src/config/http.config.ts
new file mode 100644
index 0000000000000000000000000000000000000000..dbf37be04aac09ddc3eba3e2eaa6db1b8b9ce1f8
--- /dev/null
+++ b/apps/did-manager/src/config/http.config.ts
@@ -0,0 +1,6 @@
+import { registerAs } from '@nestjs/config';
+
+export const httpConfig = registerAs('http', () => ({
+  host: process.env.HTTP_HOST || '0.0.0.0',
+  port: Number(process.env.HTTP_PORT) || 3000,
+}));
diff --git a/apps/did-manager/src/config/nats.config.ts b/apps/did-manager/src/config/nats.config.ts
new file mode 100644
index 0000000000000000000000000000000000000000..194053c2e2e44070e34b8547b4a15819d02d9b75
--- /dev/null
+++ b/apps/did-manager/src/config/nats.config.ts
@@ -0,0 +1,8 @@
+import { registerAs } from '@nestjs/config';
+
+export const natsConfig = registerAs('nats', () => ({
+  url: process.env.NATS_URL || 'nats://localhost:4222',
+  user: process.env.NATS_USER,
+  password: process.env.NATS_PASSWORD,
+  monitoringUrl: process.env.NATS_MONITORING_URL || 'http://localhost:8222',
+}));
diff --git a/apps/did-manager/src/config/validation.ts b/apps/did-manager/src/config/validation.ts
new file mode 100644
index 0000000000000000000000000000000000000000..e9abf25ab2e96d0fc30843b3dba5147b4b91074b
--- /dev/null
+++ b/apps/did-manager/src/config/validation.ts
@@ -0,0 +1,11 @@
+import Joi from 'joi';
+
+export const validationSchema = Joi.object({
+  HTTP_HOST: Joi.string(),
+  HTTP_PORT: Joi.number(),
+
+  NATS_URL: Joi.string().uri(),
+  NATS_USER: Joi.string().optional(),
+  NATS_PASSWORD: Joi.string().optional(),
+  NATS_MONITORING_URL: Joi.string().uri(),
+});
diff --git a/apps/did-manager/src/dids/__tests__/dids.controller.spec.ts b/apps/did-manager/src/dids/__tests__/dids.controller.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..79219ca5067ae088861e121091761f39914b361a
--- /dev/null
+++ b/apps/did-manager/src/dids/__tests__/dids.controller.spec.ts
@@ -0,0 +1,126 @@
+import type { TestingModule } from '@nestjs/testing';
+import type {
+  EventDidsDidConfiguration,
+  EventDidsRegisterIndyFromSeed,
+  EventDidsRegisterIndyFromSeedInput,
+  EventDidsResolve,
+} from '@ocm/shared';
+
+import { Test } from '@nestjs/testing';
+import { Subject, of, takeUntil } from 'rxjs';
+
+import { NATS_CLIENT } from '../../common/constants.js';
+import { DIDsController } from '../dids.controller.js';
+import { DIDsService } from '../dids.service.js';
+
+describe('DIDsController', () => {
+  const natsClientMock = {};
+
+  let controller: DIDsController;
+  let service: DIDsService;
+
+  beforeEach(async () => {
+    const module: TestingModule = await Test.createTestingModule({
+      controllers: [DIDsController],
+      providers: [
+        { provide: NATS_CLIENT, useValue: natsClientMock },
+        DIDsService,
+      ],
+    }).compile();
+
+    controller = module.get<DIDsController>(DIDsController);
+    service = module.get<DIDsService>(DIDsService);
+  });
+
+  describe('resolve', () => {
+    it('should call service.resolve with the correct arguments', (done) => {
+      const unsubscribe$ = new Subject<void>();
+      const tenantId = 'tenantId';
+      const did = 'did';
+      const expectedResult = {} as EventDidsResolve['data'];
+
+      jest.spyOn(service, 'resolve').mockReturnValueOnce(of(expectedResult));
+
+      controller
+        .resolve({ tenantId }, { did })
+        .pipe(takeUntil(unsubscribe$))
+        .subscribe((result) => {
+          expect(service.resolve).toHaveBeenCalledWith(tenantId, did);
+          expect(result).toStrictEqual(expectedResult);
+
+          unsubscribe$.next();
+          unsubscribe$.complete();
+
+          done();
+        });
+    });
+  });
+
+  describe('registerFromSeed', () => {
+    it('should call service.registerFromSeed with the correct arguments', (done) => {
+      const unsubscribe$ = new Subject<void>();
+      const tenantId = 'tenantId';
+      const seed = 'seed';
+      const services: EventDidsRegisterIndyFromSeedInput['services'] = [
+        {
+          identifier: 'serviceId',
+          type: 'serviceType',
+          url: 'serviceUrl',
+        },
+      ];
+      const expectedResult = {} as EventDidsRegisterIndyFromSeed['data'];
+
+      jest
+        .spyOn(service, 'registerFromSeed')
+        .mockReturnValueOnce(of(expectedResult));
+
+      controller
+        .registerFromSeed({ tenantId }, { seed, services })
+        .pipe(takeUntil(unsubscribe$))
+        .subscribe((result) => {
+          expect(service.registerFromSeed).toHaveBeenCalledWith(
+            tenantId,
+            seed,
+            services,
+          );
+          expect(result).toStrictEqual(expectedResult);
+
+          unsubscribe$.next();
+          unsubscribe$.complete();
+
+          done();
+        });
+    });
+  });
+
+  describe('getConfiguration', () => {
+    it('should call service.getConfiguration with the correct arguments', (done) => {
+      const unsubscribe$ = new Subject<void>();
+      const tenantId = 'tenantId';
+      const domain = 'domain';
+      const expiryTime = 123;
+      const expectedResult = {} as EventDidsDidConfiguration['data'];
+
+      jest
+        .spyOn(service, 'getConfiguration')
+        .mockReturnValueOnce(of(expectedResult));
+
+      controller
+        .getConfiguration({ tenantId }, { domain, expiryTime })
+        .pipe(takeUntil(unsubscribe$))
+        .subscribe((result) => {
+          expect(service.getConfiguration).toHaveBeenCalledWith(
+            tenantId,
+            domain,
+            expiryTime,
+          );
+          expect(result).toStrictEqual(expectedResult);
+
+          unsubscribe$.next();
+          unsubscribe$.complete();
+
+          done();
+        });
+    });
+  });
+});
diff --git a/apps/did-manager/src/dids/__tests__/dids.module.spec.ts b/apps/did-manager/src/dids/__tests__/dids.module.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..645346937600932948ee624246665486c23ca264
--- /dev/null
+++ b/apps/did-manager/src/dids/__tests__/dids.module.spec.ts
@@ -0,0 +1,35 @@
+import { ClientsModule } from '@nestjs/microservices';
+import { Test } from '@nestjs/testing';
+
+import { NATS_CLIENT } from '../../common/constants.js';
+import { DIDsController } from '../dids.controller.js';
+import { DIDsModule } from '../dids.module.js';
+import { DIDsService } from '../dids.service.js';
+
+describe('DIDsModule', () => {
+  let didsController: DIDsController;
+  let didsService: DIDsService;
+
+  beforeEach(async () => {
+    const moduleRef = await Test.createTestingModule({
+      imports: [
+        ClientsModule.registerAsync({
+          isGlobal: true,
+          clients: [{ name: NATS_CLIENT, useFactory: () => ({}) }],
+        }),
+        DIDsModule,
+      ],
+    }).compile();
+
+    didsController = moduleRef.get<DIDsController>(DIDsController);
+    didsService = moduleRef.get<DIDsService>(DIDsService);
+  });
+
+  it('should be defined', () => {
+    expect(didsController).toBeDefined();
+    expect(didsController).toBeInstanceOf(DIDsController);
+
+    expect(didsService).toBeDefined();
+    expect(didsService).toBeInstanceOf(DIDsService);
+  });
+});
diff --git a/apps/did-manager/src/dids/__tests__/dids.service.spec.ts b/apps/did-manager/src/dids/__tests__/dids.service.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..2cda5e51a148ecc92909961a2193e4a7690a9a57
--- /dev/null
+++ b/apps/did-manager/src/dids/__tests__/dids.service.spec.ts
@@ -0,0 +1,134 @@
+import type { EventDidsRegisterIndyFromSeedInput } from '@ocm/shared';
+
+import { Test } from '@nestjs/testing';
+import {
+  EventDidsDidConfiguration,
+  EventDidsRegisterIndyFromSeed,
+  EventDidsResolve,
+} from '@ocm/shared';
+import { Subject, of, takeUntil } from 'rxjs';
+
+import { NATS_CLIENT } from '../../common/constants.js';
+import { DIDsService } from '../dids.service.js';
+
+describe('DIDsService', () => {
+  let service: DIDsService;
+  const natsClientMock = { send: jest.fn() };
+
+  beforeEach(async () => {
+    jest.resetAllMocks();
+
+    const module = await Test.createTestingModule({
+      providers: [
+        { provide: NATS_CLIENT, useValue: natsClientMock },
+        DIDsService,
+      ],
+    }).compile();
+
+    service = module.get<DIDsService>(DIDsService);
+  });
+
+  it('should be defined', () => {
+    expect(service).toBeDefined();
+  });
+
+  describe('resolve', () => {
+    it('should call natsClient.send with the correct arguments', (done) => {
+      const unsubscribe$ = new Subject<void>();
+      const tenantId = 'tenantId';
+      const did = 'did';
+      const expectedResult = {} as EventDidsResolve['data'];
+
+      natsClientMock.send.mockReturnValueOnce(
+        of(new EventDidsResolve(expectedResult, tenantId)),
+      );
+
+      service
+        .resolve(tenantId, did)
+        .pipe(takeUntil(unsubscribe$))
+        .subscribe((result) => {
+          expect(natsClientMock.send).toHaveBeenCalledWith(
+            EventDidsResolve.token,
+            { tenantId, did },
+          );
+
+          expect(result).toStrictEqual(expectedResult);
+
+          unsubscribe$.next();
+          unsubscribe$.complete();
+
+          done();
+        });
+    });
+  });
+
+  describe('registerFromSeed', () => {
+    it('should call natsClient.send with the correct arguments', (done) => {
+      const unsubscribe$ = new Subject<void>();
+      const tenantId = 'tenantId';
+      const seed = 'seed';
+      const services: EventDidsRegisterIndyFromSeedInput['services'] = [
+        {
+          type: 'indy',
+          url: 'url',
+          identifier: 'identifier',
+        },
+      ];
+      const expectedResult = {} as EventDidsRegisterIndyFromSeed['data'];
+
+      natsClientMock.send.mockReturnValueOnce(
+        of(new EventDidsRegisterIndyFromSeed(expectedResult, tenantId)),
+      );
+
+      service
+        .registerFromSeed(tenantId, seed, services)
+        .pipe(takeUntil(unsubscribe$))
+        .subscribe((result) => {
+          expect(natsClientMock.send).toHaveBeenCalledWith(
+            EventDidsRegisterIndyFromSeed.token,
+            { tenantId, seed, services },
+          );
+
+          expect(result).toStrictEqual(expectedResult);
+
+          unsubscribe$.next();
+          unsubscribe$.complete();
+
+          done();
+        });
+    });
+  });
+
+  describe('getConfiguration', () => {
+    it('should call natsClient.send with the correct arguments', (done) => {
+      const unsubscribe$ = new Subject<void>();
+      const tenantId = 'tenantId';
+      const domain = 'domain';
+      const expiryTime = 1;
+      const expectedResult: EventDidsDidConfiguration['data'] = {
+        entries: [],
+      };
+
+      natsClientMock.send.mockReturnValueOnce(
+        of(new EventDidsDidConfiguration(expectedResult, tenantId)),
+      );
+
+      service
+        .getConfiguration(tenantId, domain, expiryTime)
+        .pipe(takeUntil(unsubscribe$))
+        .subscribe((result) => {
+          expect(natsClientMock.send).toHaveBeenCalledWith(
+            EventDidsDidConfiguration.token,
+            { tenantId, domain, expiryTime },
+          );
+
+          expect(result).toStrictEqual(expectedResult);
+
+          unsubscribe$.next();
+          unsubscribe$.complete();
+
+          done();
+        });
+    });
+  });
+});
diff --git a/apps/did-manager/src/dids/dids.controller.ts b/apps/did-manager/src/dids/dids.controller.ts
new file mode 100644
index 0000000000000000000000000000000000000000..de4d1b86e2818ffb15800d61766a4e647cf1d301
--- /dev/null
+++ b/apps/did-manager/src/dids/dids.controller.ts
@@ -0,0 +1,264 @@
+import {
+  Body,
+  Controller,
+  Get,
+  HttpCode,
+  HttpStatus,
+  Param,
+  Post,
+  Query,
+  UseInterceptors,
+  UsePipes,
+  ValidationPipe,
+} from '@nestjs/common';
+import { ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';
+import { MultitenancyParams, ResponseFormatInterceptor } from '@ocm/shared';
+
+import { DIDsService } from './dids.service.js';
+import { GetConfigurationPayload } from './dto/get-configuration.dto.js';
+import { RegisterFromSeedPayload } from './dto/register-from-seed.dto.js';
+import { ResolveParams } from './dto/resolve.dto.js';
+
+@Controller()
+@ApiTags('DIDs')
+@UsePipes(new ValidationPipe({ transform: true, whitelist: true }))
+@UseInterceptors(new ResponseFormatInterceptor())
+export class DIDsController {
+  public constructor(private readonly service: DIDsService) {}
+
+  @Get(':did')
+  @ApiOperation({
+    summary: 'Resolve DID',
+    description: 'Resolve DID',
+  })
+  @ApiResponse({
+    status: HttpStatus.OK,
+    description: 'DID resolved successfully',
+    content: {
+      'application/json': {
+        schema: {},
+        examples: {
+          'DID resolved successfully': {
+            value: {
+              statusCode: 200,
+              message: 'DID resolved successfully',
+              data: {},
+            },
+          },
+        },
+      },
+    },
+  })
+  @ApiResponse({
+    status: HttpStatus.NOT_FOUND,
+    description: 'DID not found',
+    content: {
+      'application/json': {
+        schema: {},
+        examples: {
+          'Tenant not found': {
+            value: {
+              statusCode: 404,
+              message: 'Tenant not found',
+            },
+          },
+          'DID not found': {
+            value: {
+              statusCode: 404,
+              message: 'DID not found',
+            },
+          },
+        },
+      },
+    },
+  })
+  @ApiResponse({
+    status: HttpStatus.BAD_REQUEST,
+    description: 'Invalid DID',
+    content: {
+      'application/json': {
+        schema: {},
+        examples: {
+          'Invalid DID': {
+            value: {
+              statusCode: 400,
+              message: 'Invalid DID',
+            },
+          },
+        },
+      },
+    },
+  })
+  @ApiResponse({
+    status: HttpStatus.INTERNAL_SERVER_ERROR,
+    description: 'Something went wrong',
+    content: {
+      'application/json': {
+        schema: {},
+        examples: {
+          'Something went wrong': {
+            value: {
+              statusCode: 500,
+              message: 'Something went wrong',
+              error: 'Internal Server Error',
+            },
+          },
+        },
+      },
+    },
+  })
+  public resolve(
+    @Query() { tenantId }: MultitenancyParams,
+    @Param() { did }: ResolveParams,
+  ) {
+    return this.service.resolve(tenantId, did);
+  }
+
+  @Post()
+  @ApiOperation({
+    summary: 'Register DID from seed',
+    description: 'Register DID from seed',
+  })
+  @ApiResponse({
+    status: HttpStatus.OK,
+    description: 'DID registered successfully',
+    content: {
+      'application/json': {
+        schema: {},
+        examples: {
+          'DID registered successfully': {
+            value: {
+              statusCode: 200,
+              message: 'DID registered successfully',
+              data: {},
+            },
+          },
+        },
+      },
+    },
+  })
+  @ApiResponse({
+    status: HttpStatus.BAD_REQUEST,
+    description: 'Invalid seed',
+    content: {
+      'application/json': {
+        schema: {},
+        examples: {
+          'Invalid seed': {
+            value: {
+              statusCode: 400,
+              message: 'Invalid seed',
+            },
+          },
+        },
+      },
+    },
+  })
+  @ApiResponse({
+    status: HttpStatus.NOT_FOUND,
+    description: 'Tenant not found',
+    content: {
+      'application/json': {
+        schema: {},
+        examples: {
+          'Tenant not found': {
+            value: {
+              statusCode: 404,
+              message: 'Tenant not found',
+            },
+          },
+        },
+      },
+    },
+  })
+  @ApiResponse({
+    status: HttpStatus.INTERNAL_SERVER_ERROR,
+    description: 'Something went wrong',
+    content: {
+      'application/json': {
+        schema: {},
+        examples: {
+          'Something went wrong': {
+            value: {
+              statusCode: 500,
+              message: 'Something went wrong',
+              error: 'Internal Server Error',
+            },
+          },
+        },
+      },
+    },
+  })
+  public registerFromSeed(
+    @Query() { tenantId }: MultitenancyParams,
+    @Body() { seed, services }: RegisterFromSeedPayload,
+  ) {
+    return this.service.registerFromSeed(tenantId, seed, services);
+  }
+
+  @Post('configuration')
+  @HttpCode(HttpStatus.OK)
+  @ApiOperation({
+    summary: 'Get DID configuration',
+    description: 'Get DID configuration',
+  })
+  @ApiResponse({
+    status: HttpStatus.OK,
+    description: 'DID configuration fetched successfully',
+    content: {
+      'application/json': {
+        schema: {},
+        examples: {
+          'DID configuration fetched successfully': {
+            value: {
+              statusCode: 200,
+              message: 'DID configuration fetched successfully',
+              data: {},
+            },
+          },
+        },
+      },
+    },
+  })
+  @ApiResponse({
+    status: HttpStatus.NOT_FOUND,
+    description: 'Tenant not found',
+    content: {
+      'application/json': {
+        schema: {},
+        examples: {
+          'Tenant not found': {
+            value: {
+              statusCode: 404,
+              message: 'Tenant not found',
+            },
+          },
+        },
+      },
+    },
+  })
+  @ApiResponse({
+    status: HttpStatus.INTERNAL_SERVER_ERROR,
+    description: 'Something went wrong',
+    content: {
+      'application/json': {
+        schema: {},
+        examples: {
+          'Something went wrong': {
+            value: {
+              statusCode: 500,
+              message: 'Something went wrong',
+              error: 'Internal Server Error',
+            },
+          },
+        },
+      },
+    },
+  })
+  public getConfiguration(
+    @Query() { tenantId }: MultitenancyParams,
+    @Body() { domain, expiryTime }: GetConfigurationPayload,
+  ) {
+    return this.service.getConfiguration(tenantId, domain, expiryTime);
+  }
+}
diff --git a/apps/did-manager/src/dids/dids.module.ts b/apps/did-manager/src/dids/dids.module.ts
new file mode 100644
index 0000000000000000000000000000000000000000..2b34aeb0f7c7988a55a5ba368e74b25583993d04
--- /dev/null
+++ b/apps/did-manager/src/dids/dids.module.ts
@@ -0,0 +1,10 @@
+import { Module } from '@nestjs/common';
+
+import { DIDsController } from './dids.controller.js';
+import { DIDsService } from './dids.service.js';
+
+@Module({
+  providers: [DIDsService],
+  controllers: [DIDsController],
+})
+export class DIDsModule {}
diff --git a/apps/did-manager/src/dids/dids.service.ts b/apps/did-manager/src/dids/dids.service.ts
new file mode 100644
index 0000000000000000000000000000000000000000..927325e4a16ad4e584fd79e30b5ea8ab0353373a
--- /dev/null
+++ b/apps/did-manager/src/dids/dids.service.ts
@@ -0,0 +1,58 @@
+import type {
+  EventDidsDidConfigurationInput,
+  EventDidsRegisterIndyFromSeedInput,
+  EventDidsResolveInput,
+} from '@ocm/shared';
+
+import { Inject, Injectable } from '@nestjs/common';
+import { ClientProxy } from '@nestjs/microservices';
+import {
+  EventDidsDidConfiguration,
+  EventDidsRegisterIndyFromSeed,
+  EventDidsResolve,
+} from '@ocm/shared';
+import { map } from 'rxjs';
+
+import { NATS_CLIENT } from '../common/constants.js';
+
+@Injectable()
+export class DIDsService {
+  public constructor(
+    @Inject(NATS_CLIENT) private readonly natsClient: ClientProxy,
+  ) {}
+
+  public resolve(tenantId: string, did: EventDidsResolveInput['did']) {
+    return this.natsClient
+      .send<
+        EventDidsResolve,
+        EventDidsResolveInput
+      >(EventDidsResolve.token, { tenantId, did })
+      .pipe(map(({ data }) => data));
+  }
+
+  public registerFromSeed(
+    tenantId: string,
+    seed: EventDidsRegisterIndyFromSeedInput['seed'],
+    services?: EventDidsRegisterIndyFromSeedInput['services'],
+  ) {
+    return this.natsClient
+      .send<
+        EventDidsRegisterIndyFromSeed,
+        EventDidsRegisterIndyFromSeedInput
+      >(EventDidsRegisterIndyFromSeed.token, { tenantId, seed, services })
+      .pipe(map(({ data }) => data));
+  }
+
+  public getConfiguration(
+    tenantId: string,
+    domain: EventDidsDidConfigurationInput['domain'],
+    expiryTime: EventDidsDidConfigurationInput['expiryTime'],
+  ) {
+    return this.natsClient
+      .send<
+        EventDidsDidConfiguration,
+        EventDidsDidConfigurationInput
+      >(EventDidsDidConfiguration.token, { tenantId, domain, expiryTime })
+      .pipe(map(({ data }) => data));
+  }
+}
diff --git a/apps/did-manager/src/dids/dto/get-configuration.dto.ts b/apps/did-manager/src/dids/dto/get-configuration.dto.ts
new file mode 100644
index 0000000000000000000000000000000000000000..7b93f1ac9885984dcc1242a5e89443fa14254596
--- /dev/null
+++ b/apps/did-manager/src/dids/dto/get-configuration.dto.ts
@@ -0,0 +1,9 @@
+import { IsNumber, IsString } from 'class-validator';
+
+export class GetConfigurationPayload {
+  @IsString()
+  public domain: string;
+
+  @IsNumber()
+  public expiryTime: number;
+}
diff --git a/apps/did-manager/src/dids/dto/register-from-seed.dto.ts b/apps/did-manager/src/dids/dto/register-from-seed.dto.ts
new file mode 100644
index 0000000000000000000000000000000000000000..6b06678b68b4af95ab033f660b2f19c5f8547a2a
--- /dev/null
+++ b/apps/did-manager/src/dids/dto/register-from-seed.dto.ts
@@ -0,0 +1,28 @@
+import { ApiProperty } from '@nestjs/swagger';
+import { IsString, IsArray } from 'class-validator';
+
+export class RegisterFromSeedPayload {
+  @IsString()
+  @ApiProperty({
+    description: 'Seed to use for DID generation',
+    example: '000000000000000000000000Steward1',
+  })
+  public seed: string;
+
+  @IsArray()
+  @ApiProperty({
+    description: 'Services to associate with DID',
+    example: [
+      {
+        identifier: 'example',
+        url: 'https://example.com',
+        type: 'example',
+      },
+    ],
+  })
+  public services?: Array<{
+    identifier: string;
+    url: string;
+    type: string;
+  }>;
+}
diff --git a/apps/did-manager/src/dids/dto/resolve.dto.ts b/apps/did-manager/src/dids/dto/resolve.dto.ts
new file mode 100644
index 0000000000000000000000000000000000000000..3b75806484d9c3a26481c477b1596b9000561bcb
--- /dev/null
+++ b/apps/did-manager/src/dids/dto/resolve.dto.ts
@@ -0,0 +1,12 @@
+import { ApiProperty } from '@nestjs/swagger';
+import { IsString, Matches } from 'class-validator';
+
+export class ResolveParams {
+  @IsString()
+  @Matches(/^did:[a-z0-9]+:.+$/)
+  @ApiProperty({
+    description: 'DID to resolve',
+    example: 'did:example:123',
+  })
+  public did: string;
+}
diff --git a/apps/did-manager/src/main.ts b/apps/did-manager/src/main.ts
new file mode 100644
index 0000000000000000000000000000000000000000..fa521d4f2bbaf856fcbbf34f8db9558e730fa760
--- /dev/null
+++ b/apps/did-manager/src/main.ts
@@ -0,0 +1,55 @@
+/* c8 ignore start */
+import type { ConfigType } from '@nestjs/config';
+import type { MicroserviceOptions, NatsOptions } from '@nestjs/microservices';
+
+import { Logger, VersioningType } from '@nestjs/common';
+import { NestFactory } from '@nestjs/core';
+import { Transport } from '@nestjs/microservices';
+import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
+
+import { Application } from './application.js';
+import { httpConfig } from './config/http.config.js';
+import { natsConfig } from './config/nats.config.js';
+
+const app = await NestFactory.create(Application);
+app.enableCors();
+
+const { url, user, password } = app.get(natsConfig.KEY) as ConfigType<
+  typeof natsConfig
+>;
+
+const microserviceOptions: Required<NatsOptions> = {
+  transport: Transport.NATS,
+  options: {
+    servers: [url],
+  },
+};
+
+if (user && password) {
+  microserviceOptions.options.user = user;
+  microserviceOptions.options.pass = password;
+}
+
+app.connectMicroservice<MicroserviceOptions>(microserviceOptions);
+
+app.enableVersioning({
+  defaultVersion: ['1'],
+  type: VersioningType.URI,
+});
+
+const swaggerConfig = new DocumentBuilder()
+  .setTitle('Gaia-X OCM DID Manager API')
+  .setDescription('API documentation for Gaia-X OCM DID Manager')
+  .setVersion('1.0')
+  .build();
+
+const document = SwaggerModule.createDocument(app, swaggerConfig);
+
+SwaggerModule.setup('/', app, document);
+await app.startAllMicroservices();
+
+const { host, port } = app.get(httpConfig.KEY) as ConfigType<typeof httpConfig>;
+await app.listen(port as number, host as string);
+
+Logger.log(`Application is running on: ${await app.getUrl()}`);
+/* c8 ignore stop */
diff --git a/apps/did-manager/tsconfig.build.json b/apps/did-manager/tsconfig.build.json
new file mode 100644
index 0000000000000000000000000000000000000000..3e5ab438230b6cbd30a5825fc562c485a89ff95d
--- /dev/null
+++ b/apps/did-manager/tsconfig.build.json
@@ -0,0 +1,9 @@
+{
+  "extends": "../../tsconfig.build.json",
+  "compilerOptions": {
+    "baseUrl": ".",
+    "outDir": "./dist",
+    "rootDir": "./src"
+  },
+  "exclude": ["node_modules", "**/test", "**/dist", "**/*spec.ts"]
+}
diff --git a/apps/did-manager/tsconfig.json b/apps/did-manager/tsconfig.json
new file mode 100644
index 0000000000000000000000000000000000000000..4082f16a5d91ce6f21a9092b14170eeecc8f1d75
--- /dev/null
+++ b/apps/did-manager/tsconfig.json
@@ -0,0 +1,3 @@
+{
+  "extends": "../../tsconfig.json"
+}
diff --git a/apps/did-manager/tsconfig.production.json b/apps/did-manager/tsconfig.production.json
new file mode 100644
index 0000000000000000000000000000000000000000..45f85dfe5daf11a59e2fac464fa15940a2f50200
--- /dev/null
+++ b/apps/did-manager/tsconfig.production.json
@@ -0,0 +1,9 @@
+{
+  "extends": "../../tsconfig.production.json",
+  "compilerOptions": {
+    "baseUrl": ".",
+    "outDir": "./dist",
+    "rootDir": "./src"
+  },
+  "exclude": ["node_modules", "**/test", "**/dist", "**/*spec.ts"]
+}
diff --git a/apps/shared/src/events/credentialEvents.ts b/apps/shared/src/events/credentialEvents.ts
index e52cdbf812ad908da705d976dbf5eaab48be7ad3..a3980307cdaf6f99c66dbd35a8069cfafb6e1a13 100644
--- a/apps/shared/src/events/credentialEvents.ts
+++ b/apps/shared/src/events/credentialEvents.ts
@@ -50,6 +50,27 @@ export class EventAnonCredsCredentialsGetById extends BaseEvent<CredentialExchan
   }
 }
 
+export type EventDidcommAnonCredsCredentialsAcceptOfferInput = BaseEventInput<{
+  credentialId: string;
+}>;
+export class EventDidcommAnonCredsCredentialsAcceptOffer extends BaseEvent<CredentialExchangeRecord> {
+  public static token = 'didcomm.anoncreds.credentials.acceptOffer';
+
+  public get instance() {
+    return JsonTransformer.fromJSON(this.data, CredentialExchangeRecord);
+  }
+
+  public static fromEvent(e: EventDidcommAnonCredsCredentialsOffer) {
+    return new EventDidcommAnonCredsCredentialsOffer(
+      e.data,
+      e.tenantId,
+      e.id,
+      e.type,
+      e.timestamp,
+    );
+  }
+}
+
 export type EventDidcommAnonCredsCredentialsOfferInput = BaseEventInput<{
   connectionId: string;
   credentialDefinitionId: string;
diff --git a/apps/ssi-abstraction/src/agent/anoncredsCredentials/anoncredsCredentials.controller.ts b/apps/ssi-abstraction/src/agent/anoncredsCredentials/anoncredsCredentials.controller.ts
index b4a7841072c40c3f344c31e35f09e6b8f1ffe9ec..963794535c06317035b136e331ee1883c053389e 100644
--- a/apps/ssi-abstraction/src/agent/anoncredsCredentials/anoncredsCredentials.controller.ts
+++ b/apps/ssi-abstraction/src/agent/anoncredsCredentials/anoncredsCredentials.controller.ts
@@ -15,6 +15,8 @@ import {
   EventAnonCredsCredentialsGetAllInput,
   EventAnonCredsCredentialsGetById,
   EventAnonCredsCredentialsGetByIdInput,
+  EventDidcommAnonCredsCredentialsAcceptOffer,
+  EventDidcommAnonCredsCredentialsAcceptOfferInput,
   EventDidcommAnonCredsCredentialsOffer,
   EventDidcommAnonCredsCredentialsOfferInput,
   EventDidcommAnonCredsCredentialsOfferToSelf,
@@ -97,6 +99,16 @@ export class AnonCredsCredentialsController {
     );
   }
 
+  @MessagePattern(EventDidcommAnonCredsCredentialsAcceptOffer.token)
+  public async acceptOffer(
+    options: EventDidcommAnonCredsCredentialsAcceptOfferInput,
+  ): Promise<EventDidcommAnonCredsCredentialsAcceptOffer> {
+    return new EventDidcommAnonCredsCredentialsAcceptOffer(
+      await this.credentialsService.acceptOffer(options),
+      options.tenantId,
+    );
+  }
+
   @MessagePattern(EventDidcommAnonCredsCredentialsOffer.token)
   public async offer(
     options: EventDidcommAnonCredsCredentialsOfferInput,
diff --git a/apps/ssi-abstraction/src/agent/anoncredsCredentials/anoncredsCredentials.service.ts b/apps/ssi-abstraction/src/agent/anoncredsCredentials/anoncredsCredentials.service.ts
index 1230d74b9f671c2bfc2161760572c4a13815ed0f..103f0c2ba80d4795a13fe4d0de965991cc2ae266 100644
--- a/apps/ssi-abstraction/src/agent/anoncredsCredentials/anoncredsCredentials.service.ts
+++ b/apps/ssi-abstraction/src/agent/anoncredsCredentials/anoncredsCredentials.service.ts
@@ -16,6 +16,8 @@ import type {
   EventAnonCredsCredentialsDeleteByIdInput,
   EventAnonCredsCredentialsGetAllInput,
   EventAnonCredsCredentialsGetByIdInput,
+  EventDidcommAnonCredsCredentialsAcceptOffer,
+  EventDidcommAnonCredsCredentialsAcceptOfferInput,
   EventDidcommAnonCredsCredentialsOffer,
   EventDidcommAnonCredsCredentialsOfferInput,
   EventDidcommAnonCredsCredentialsOfferToSelf,
@@ -24,8 +26,8 @@ import type {
 
 import {
   AutoAcceptCredential,
-  CredentialState,
   CredentialEventTypes,
+  CredentialState,
 } from '@credo-ts/core';
 import { GenericRecord } from '@credo-ts/core/build/modules/generic-records/repository/GenericRecord.js';
 import { Injectable } from '@nestjs/common';
@@ -149,6 +151,19 @@ export class AnonCredsCredentialsService {
     });
   }
 
+  public async acceptOffer({
+    tenantId,
+    credentialId,
+  }: EventDidcommAnonCredsCredentialsAcceptOfferInput): Promise<
+    EventDidcommAnonCredsCredentialsAcceptOffer['data']
+  > {
+    return this.withTenantService.invoke(tenantId, (t) =>
+      t.credentials.acceptOffer({
+        credentialRecordId: credentialId,
+      }),
+    );
+  }
+
   public async offer({
     tenantId,
     connectionId,
diff --git a/apps/ssi-abstraction/test/anoncredsCredentials.e2e-spec.ts b/apps/ssi-abstraction/test/anoncredsCredentials.e2e-spec.ts
index 672778b11dc0f226e4c035975d43ec3c9cd32f62..e90864892823e43c0af05a087c5e4c3ee1486b2f 100644
--- a/apps/ssi-abstraction/test/anoncredsCredentials.e2e-spec.ts
+++ b/apps/ssi-abstraction/test/anoncredsCredentials.e2e-spec.ts
@@ -1,28 +1,36 @@
 import type { INestApplication } from '@nestjs/common';
 import type { ClientProxy } from '@nestjs/microservices';
 import type {
-  EventAnonCredsCredentialRequestGetAllInput,
-  EventAnonCredsCredentialsGetAllInput,
-  EventAnonCredsCredentialsGetByIdInput,
-  EventDidcommAnonCredsCredentialsOfferToSelfInput,
   EventAnonCredsCredentialOfferGetAllInput,
   EventAnonCredsCredentialOfferGetByIdInput,
+  EventAnonCredsCredentialRequestGetAllInput,
   EventAnonCredsCredentialRequestGetByIdInput,
   EventAnonCredsCredentialsDeleteByIdInput,
+  EventAnonCredsCredentialsGetAllInput,
+  EventAnonCredsCredentialsGetByIdInput,
+  EventDidcommAnonCredsCredentialsAcceptOffer,
+  EventDidcommAnonCredsCredentialsAcceptOfferInput,
+  EventDidcommAnonCredsCredentialsOfferInput,
+  EventDidcommAnonCredsCredentialsOfferToSelfInput,
 } from '@ocm/shared';
 
-import { AutoAcceptCredential, CredentialExchangeRecord } from '@credo-ts/core';
+import {
+  AutoAcceptCredential,
+  CredentialExchangeRecord,
+  CredentialState,
+} from '@credo-ts/core';
 import { ClientsModule, Transport } from '@nestjs/microservices';
 import { Test } from '@nestjs/testing';
 import {
-  EventAnonCredsCredentialsDeleteById,
   EventAnonCredsCredentialOfferGetAll,
   EventAnonCredsCredentialOfferGetById,
   EventAnonCredsCredentialRequestGetAll,
   EventAnonCredsCredentialRequestGetById,
+  EventAnonCredsCredentialsDeleteById,
   EventAnonCredsCredentialsGetAll,
   EventAnonCredsCredentialsGetById,
   EventAnonCredsProofsDeleteById,
+  EventDidcommAnonCredsCredentialsOffer,
   EventDidcommAnonCredsCredentialsOfferToSelf,
 } from '@ocm/shared';
 import { randomBytes } from 'crypto';
@@ -50,6 +58,7 @@ describe('Credentials', () => {
 
   let issuerDid: string;
   let credentialDefinitionId: string;
+  let connectionId: string;
 
   beforeAll(async () => {
     const moduleRef = await Test.createTestingModule({
@@ -111,6 +120,18 @@ describe('Credentials', () => {
       });
 
     credentialDefinitionId = cdi;
+
+    const connectionService = app.get(ConnectionsService);
+    const { invitationUrl } = await connectionService.createInvitation({
+      tenantId,
+    });
+
+    const { id: cId } = await connectionService.receiveInvitationFromUrl({
+      tenantId,
+      invitationUrl,
+    });
+
+    connectionId = cId;
   });
 
   afterAll(async () => {
@@ -197,6 +218,45 @@ describe('Credentials', () => {
     expect(eventInstance.instance).toEqual(null);
   });
 
+  it(EventDidcommAnonCredsCredentialsOffer.token, async () => {
+    const attributes = [
+      { name: 'Name', value: 'Berend' },
+      { name: 'Age', value: '25' },
+    ];
+
+    const response$ = client.send<
+      EventDidcommAnonCredsCredentialsOffer,
+      EventDidcommAnonCredsCredentialsOfferInput
+    >(EventDidcommAnonCredsCredentialsOffer.token, {
+      tenantId,
+      connectionId,
+      attributes,
+      credentialDefinitionId,
+    });
+
+    const response = await firstValueFrom(response$);
+    const eventInstance =
+      EventDidcommAnonCredsCredentialsOffer.fromEvent(response);
+
+    await new Promise((r) => setTimeout(r, 2000));
+
+    const acceptResponse$ = client.send<
+      EventDidcommAnonCredsCredentialsAcceptOffer,
+      EventDidcommAnonCredsCredentialsAcceptOfferInput
+    >(EventDidcommAnonCredsCredentialsOffer.token, {
+      tenantId,
+      credentialId: eventInstance.instance.id,
+    });
+
+    const acceptResponse = await firstValueFrom(acceptResponse$);
+    const acceptEventInstance =
+      EventAnonCredsCredentialsGetById.fromEvent(acceptResponse);
+
+    expect(acceptEventInstance.instance).toMatchObject({
+      state: CredentialState.RequestSent,
+    });
+  });
+
   it(EventDidcommAnonCredsCredentialsOfferToSelf.token, async () => {
     const attributes = [
       { name: 'Name', value: 'Berend' },
diff --git a/docker-compose.yml b/docker-compose.yml
index 6422563cd76462d503bb270acc6dc38737663c28..6f1b0df4da1d2cf847f9e799426e5de5f7f7c44b 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -137,3 +137,20 @@ services:
       - '4004:3000'
     depends_on:
       - nats
+
+  did-manager:
+    build:
+      args:
+        - SERVICE=did-manager
+    init: true
+    environment:
+      HTTP_HOST: 0.0.0.0
+      HTTP_PORT: 3000
+      NATS_URL: nats://nats:4222
+      NATS_USER: nats_user
+      NATS_PASSWORD: Rw+dYIymAQm9H6ELLNwSuGo1812jqQ==
+      NATS_MONITORING_URL: http://nats:8222
+    ports:
+      - '4006:3000'
+    depends_on:
+      - nats
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 84ed5d7c81df6e198a90e030b08b9b2dfe2af5c7..5fa7773ca395be03ce017e45c732830a24287119 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -248,6 +248,88 @@ importers:
         specifier: ^5.3.2
         version: 5.3.3
 
+  apps/did-manager:
+    dependencies:
+      '@nestjs/common':
+        specifier: ^10.3.0
+        version: 10.3.0(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.14)(rxjs@7.8.1)
+      '@nestjs/config':
+        specifier: ^3.1.1
+        version: 3.1.1(@nestjs/common@10.3.0)(reflect-metadata@0.1.14)
+      '@nestjs/core':
+        specifier: ^10.3.0
+        version: 10.3.0(@nestjs/common@10.3.0)(@nestjs/microservices@10.3.0)(@nestjs/platform-express@10.3.0)(reflect-metadata@0.1.14)(rxjs@7.8.1)
+      '@nestjs/microservices':
+        specifier: ^10.3.0
+        version: 10.3.0(@nestjs/common@10.3.0)(@nestjs/core@10.3.0)(nats@2.19.0)(reflect-metadata@0.1.14)(rxjs@7.8.1)
+      '@nestjs/platform-express':
+        specifier: ^10.3.0
+        version: 10.3.0(@nestjs/common@10.3.0)(@nestjs/core@10.3.0)
+      '@nestjs/swagger':
+        specifier: ^7.2.0
+        version: 7.2.0(@nestjs/common@10.3.0)(@nestjs/core@10.3.0)(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.14)
+      '@ocm/shared':
+        specifier: workspace:*
+        version: link:../shared
+      class-transformer:
+        specifier: ^0.5.1
+        version: 0.5.1
+      class-validator:
+        specifier: ^0.14.0
+        version: 0.14.1
+      express:
+        specifier: ^4.17.3
+        version: 4.18.2
+      joi:
+        specifier: ^17.11.0
+        version: 17.11.1
+      nats:
+        specifier: ^2.18.0
+        version: 2.19.0
+      reflect-metadata:
+        specifier: ^0.1.13
+        version: 0.1.14
+      rxjs:
+        specifier: ^7.8.1
+        version: 7.8.1
+    devDependencies:
+      '@nestjs/cli':
+        specifier: ^10.3.0
+        version: 10.3.0(@swc/cli@0.1.63)(@swc/core@1.3.103)
+      '@nestjs/schematics':
+        specifier: ^10.1.0
+        version: 10.1.0(chokidar@3.5.3)(typescript@5.3.3)
+      '@nestjs/testing':
+        specifier: ^10.3.0
+        version: 10.3.0(@nestjs/common@10.3.0)(@nestjs/core@10.3.0)(@nestjs/microservices@10.3.0)(@nestjs/platform-express@10.3.0)
+      '@swc/cli':
+        specifier: ^0.1.62
+        version: 0.1.63(@swc/core@1.3.103)
+      '@swc/core':
+        specifier: ^1.3.96
+        version: 1.3.103
+      '@swc/jest':
+        specifier: ^0.2.29
+        version: 0.2.29(@swc/core@1.3.103)
+      '@types/express':
+        specifier: ^4.17.21
+        version: 4.17.21
+      '@types/jest':
+        specifier: ^29.5.8
+        version: 29.5.11
+      '@types/node':
+        specifier: ^20.9.0
+        version: 20.11.5
+      jest:
+        specifier: ^29.7.0
+        version: 29.7.0(@types/node@20.11.5)(ts-node@10.9.2)
+      rimraf:
+        specifier: ^5.0.5
+        version: 5.0.5
+      typescript:
+        specifier: ^5.3.2
+        version: 5.3.3
+
   apps/proof-manager:
     dependencies:
       '@nestjs/common':