diff --git a/apps/shared/src/events/proofEvents.ts b/apps/shared/src/events/proofEvents.ts
new file mode 100644
index 0000000000000000000000000000000000000000..b40e17a5e327d382c7098621110fb0139504fc2f
--- /dev/null
+++ b/apps/shared/src/events/proofEvents.ts
@@ -0,0 +1,106 @@
+import type { BaseEventInput } from './baseEvents.js';
+import type {
+  AnonCredsPredicateType,
+  AnonCredsProofRequestRestriction,
+} from '@aries-framework/anoncreds';
+
+import { JsonTransformer, ProofExchangeRecord } from '@aries-framework/core';
+
+import { BaseEvent } from './baseEvents.js';
+
+export type EventAnonCredsProofsGetAllInput = BaseEventInput;
+export class EventAnonCredsProofsGetAll extends BaseEvent<
+  Array<ProofExchangeRecord>
+> {
+  public static token = 'anoncreds.proofs.getAll';
+
+  public get instance() {
+    return this.data.map((d) =>
+      JsonTransformer.fromJSON(d, ProofExchangeRecord),
+    );
+  }
+
+  public static fromEvent(e: EventAnonCredsProofsGetAll) {
+    return new EventAnonCredsProofsGetAll(
+      e.data,
+      e.tenantId,
+      e.id,
+      e.type,
+      e.timestamp,
+    );
+  }
+}
+
+export type EventAnonCredsProofsGetByIdInput = BaseEventInput<{
+  proofRecordId: string;
+}>;
+export class EventAnonCredsProofsGetById extends BaseEvent<ProofExchangeRecord | null> {
+  public static token = 'anoncreds.proofs.getById';
+
+  public get instance() {
+    return JsonTransformer.fromJSON(this.data, ProofExchangeRecord);
+  }
+
+  public static fromEvent(e: EventAnonCredsProofsGetById) {
+    return new EventAnonCredsProofsGetById(
+      e.data,
+      e.tenantId,
+      e.id,
+      e.type,
+      e.timestamp,
+    );
+  }
+}
+
+export type EventDidcommAnonCredsProofsRequestInput = BaseEventInput<{
+  connectionId: string;
+  name: string;
+  requestedAttributes: {
+    [groupName: string]: {
+      names: Array<string>;
+      restrictions?: Array<AnonCredsProofRequestRestriction>;
+    };
+  };
+  requestedPredicates: {
+    [groupName: string]: {
+      name: string;
+      predicateType: AnonCredsPredicateType;
+      predicateValue: number;
+      restrictions?: Array<AnonCredsProofRequestRestriction>;
+    };
+  };
+}>;
+export class EventDidcommAnonCredsProofsRequest extends BaseEvent<ProofExchangeRecord> {
+  public static token = 'didcomm.anoncreds.proofs.request';
+
+  public get instance() {
+    return JsonTransformer.fromJSON(this.data, ProofExchangeRecord);
+  }
+
+  public static fromEvent(e: EventDidcommAnonCredsProofsRequest) {
+    return new EventDidcommAnonCredsProofsRequest(
+      e.data,
+      e.tenantId,
+      e.id,
+      e.type,
+      e.timestamp,
+    );
+  }
+}
+
+export type EventAnonCredsProofsDeleteByIdInput = BaseEventInput<{
+  proofRecordId: string;
+}>;
+export class EventAnonCredsProofsDeleteById extends BaseEvent {
+  public static token = 'anoncreds.proofs.deleteById';
+
+  public static fromEvent(e: EventDidcommAnonCredsProofsRequest) {
+    return new EventDidcommAnonCredsProofsRequest(
+      e.data,
+      e.tenantId,
+      e.id,
+      e.type,
+      e.timestamp,
+    );
+  }
+}
diff --git a/apps/shared/src/index.ts b/apps/shared/src/index.ts
index 0bb7774a5eabfada0ee848f6d01dd53189aae94a..33b17687bc37ddff5cb7691d490c6f1f0deb8ee4 100644
--- a/apps/shared/src/index.ts
+++ b/apps/shared/src/index.ts
@@ -12,6 +12,7 @@ export * from './events/credentialDefinitionEvents.js';
 export * from './events/credentialEvents.js';
 export * from './events/credentialOfferEvents.js';
 export * from './events/credentialRequestEvents.js';
+export * from './events/proofEvents.js';
 
 export * from './dto/pagination-params.dto.js';
 export * from './dto/multitenancy-params.dto.js';
diff --git a/apps/ssi-abstraction/src/agent/agent.service.ts b/apps/ssi-abstraction/src/agent/agent.service.ts
index b1d9bd9279c2175eae5386fe50ecdccc14996a9e..27304bcb83f7317cd9ccc2c477d4ee5ae0544812 100644
--- a/apps/ssi-abstraction/src/agent/agent.service.ts
+++ b/apps/ssi-abstraction/src/agent/agent.service.ts
@@ -6,7 +6,9 @@ import type { OnApplicationShutdown } from '@nestjs/common';
 import {
   AnonCredsCredentialFormatService,
   AnonCredsModule,
+  AnonCredsProofFormatService,
   LegacyIndyCredentialFormatService,
+  LegacyIndyProofFormatService,
 } from '@aries-framework/anoncreds';
 import { AnonCredsRsModule } from '@aries-framework/anoncreds-rs';
 import { AskarModule } from '@aries-framework/askar';
@@ -23,7 +25,9 @@ import {
   LogLevel,
   PeerDidRegistrar,
   PeerDidResolver,
+  ProofsModule,
   V2CredentialProtocol,
+  V2ProofProtocol,
   WebDidResolver,
 } from '@aries-framework/core';
 import {
@@ -90,13 +94,14 @@ export class AgentService implements OnApplicationShutdown {
   }
 
   public get modules() {
-    const { autoAcceptConnection, autoAcceptCredential } =
+    const { autoAcceptConnection, autoAcceptCredential, autoAcceptProof } =
       this.configService.get('agent');
 
     return {
       connections: new ConnectionsModule({
         autoAcceptConnections: autoAcceptConnection,
       }),
+
       credentials: new CredentialsModule({
         autoAcceptCredentials: autoAcceptCredential,
         credentialProtocols: [
@@ -109,6 +114,18 @@ export class AgentService implements OnApplicationShutdown {
         ],
       }),
 
+      proofs: new ProofsModule({
+        autoAcceptProofs: autoAcceptProof,
+        proofProtocols: [
+          new V2ProofProtocol({
+            proofFormats: [
+              new AnonCredsProofFormatService(),
+              new LegacyIndyProofFormatService(),
+            ],
+          }),
+        ],
+      }),
+
       anoncredsRs: new AnonCredsRsModule({ anoncreds }),
       anoncreds: new AnonCredsModule({
         registries: [new IndyVdrAnonCredsRegistry()],
diff --git a/apps/ssi-abstraction/src/agent/anoncredsProofs/anoncredsProofs.controller.ts b/apps/ssi-abstraction/src/agent/anoncredsProofs/anoncredsProofs.controller.ts
new file mode 100644
index 0000000000000000000000000000000000000000..c29a03defeba3e94702a26aac505c0fe3bb3b7e0
--- /dev/null
+++ b/apps/ssi-abstraction/src/agent/anoncredsProofs/anoncredsProofs.controller.ts
@@ -0,0 +1,59 @@
+import { Controller } from '@nestjs/common';
+import { MessagePattern } from '@nestjs/microservices';
+import {
+  EventAnonCredsProofsDeleteById,
+  EventAnonCredsProofsDeleteByIdInput,
+  EventAnonCredsProofsGetAll,
+  EventAnonCredsProofsGetAllInput,
+  EventAnonCredsProofsGetById,
+  EventAnonCredsProofsGetByIdInput,
+  EventDidcommAnonCredsProofsRequest,
+  EventDidcommAnonCredsProofsRequestInput,
+} from '@ocm/shared';
+
+import { AnonCredsProofsService } from './anoncredsProofs.service.js';
+
+@Controller('anoncredsProofs')
+export class AnonCredsProofsController {
+  public constructor(private proofsService: AnonCredsProofsService) {}
+
+  @MessagePattern(EventAnonCredsProofsGetAll.token)
+  public async getAll(
+    options: EventAnonCredsProofsGetAllInput,
+  ): Promise<EventAnonCredsProofsGetAll> {
+    return new EventAnonCredsProofsGetAll(
+      await this.proofsService.getAll(options),
+      options.tenantId,
+    );
+  }
+
+  @MessagePattern(EventAnonCredsProofsGetById.token)
+  public async getById(
+    options: EventAnonCredsProofsGetByIdInput,
+  ): Promise<EventAnonCredsProofsGetById> {
+    return new EventAnonCredsProofsGetById(
+      await this.proofsService.getById(options),
+      options.tenantId,
+    );
+  }
+
+  @MessagePattern(EventAnonCredsProofsDeleteById.token)
+  public async deleteById(
+    options: EventAnonCredsProofsDeleteByIdInput,
+  ): Promise<EventAnonCredsProofsDeleteById> {
+    return new EventAnonCredsProofsDeleteById(
+      await this.proofsService.deleteById(options),
+      options.tenantId,
+    );
+  }
+
+  @MessagePattern(EventDidcommAnonCredsProofsRequest.token)
+  public async request(
+    options: EventDidcommAnonCredsProofsRequestInput,
+  ): Promise<EventDidcommAnonCredsProofsRequest> {
+    return new EventDidcommAnonCredsProofsRequest(
+      await this.proofsService.request(options),
+      options.tenantId,
+    );
+  }
+}
diff --git a/apps/ssi-abstraction/src/agent/anoncredsProofs/anoncredsProofs.module.ts b/apps/ssi-abstraction/src/agent/anoncredsProofs/anoncredsProofs.module.ts
new file mode 100644
index 0000000000000000000000000000000000000000..5ab1719ba2aff98122bf50ede7538dde777c3615
--- /dev/null
+++ b/apps/ssi-abstraction/src/agent/anoncredsProofs/anoncredsProofs.module.ts
@@ -0,0 +1,13 @@
+import { Module } from '@nestjs/common';
+
+import { AgentModule } from '../agent.module.js';
+
+import { AnonCredsProofsController } from './anoncredsProofs.controller.js';
+import { AnonCredsProofsService } from './anoncredsProofs.service.js';
+
+@Module({
+  imports: [AgentModule],
+  providers: [AnonCredsProofsService],
+  controllers: [AnonCredsProofsController],
+})
+export class AnonCredsProofsModule {}
diff --git a/apps/ssi-abstraction/src/agent/anoncredsProofs/anoncredsProofs.service.ts b/apps/ssi-abstraction/src/agent/anoncredsProofs/anoncredsProofs.service.ts
new file mode 100644
index 0000000000000000000000000000000000000000..4512f284466cfefbe70ba37fa258894c573f616e
--- /dev/null
+++ b/apps/ssi-abstraction/src/agent/anoncredsProofs/anoncredsProofs.service.ts
@@ -0,0 +1,88 @@
+import type {
+  EventAnonCredsProofsDeleteById,
+  EventAnonCredsProofsDeleteByIdInput,
+  EventAnonCredsProofsGetAll,
+  EventAnonCredsProofsGetAllInput,
+  EventAnonCredsProofsGetById,
+  EventAnonCredsProofsGetByIdInput,
+  EventDidcommAnonCredsProofsRequest,
+  EventDidcommAnonCredsProofsRequestInput,
+} from '@ocm/shared';
+
+import { Injectable } from '@nestjs/common';
+
+import { WithTenantService } from '../withTenantService.js';
+
+@Injectable()
+export class AnonCredsProofsService {
+  public constructor(private withTenantService: WithTenantService) {}
+
+  public async getAll({
+    tenantId,
+  }: EventAnonCredsProofsGetAllInput): Promise<
+    EventAnonCredsProofsGetAll['data']
+  > {
+    return this.withTenantService.invoke(tenantId, (t) => t.proofs.getAll());
+  }
+
+  public async getById({
+    tenantId,
+    proofRecordId,
+  }: EventAnonCredsProofsGetByIdInput): Promise<
+    EventAnonCredsProofsGetById['data']
+  > {
+    return this.withTenantService.invoke(tenantId, (t) =>
+      t.proofs.getById(proofRecordId),
+    );
+  }
+
+  public async deleteById({
+    tenantId,
+    proofRecordId,
+  }: EventAnonCredsProofsDeleteByIdInput): Promise<
+    EventAnonCredsProofsDeleteById['data']
+  > {
+    return this.withTenantService.invoke(tenantId, async (t) => {
+      await t.proofs.deleteById(proofRecordId);
+      return {};
+    });
+  }
+
+  public async request({
+    tenantId,
+    connectionId,
+    name,
+    requestedAttributes,
+    requestedPredicates,
+  }: EventDidcommAnonCredsProofsRequestInput): Promise<
+    EventDidcommAnonCredsProofsRequest['data']
+  > {
+    const transformedPredicates = Object.entries(requestedPredicates).reduce(
+      (prev, [key, value]) => ({
+        ...prev,
+        [key]: {
+          name: value.name,
+          restrictions: value.restrictions,
+          p_type: value.predicateType,
+          p_value: value.predicateValue,
+        },
+      }),
+      {},
+    );
+
+    return this.withTenantService.invoke(tenantId, (t) =>
+      t.proofs.requestProof({
+        connectionId,
+        protocolVersion: 'v2',
+        proofFormats: {
+          anoncreds: {
+            name,
+            version: '1.0',
+            requested_attributes: requestedAttributes,
+            requested_predicates: transformedPredicates,
+          },
+        },
+      }),
+    );
+  }
+}