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 72fa3311d28cf1149d297781a35d75a3b754466a..8c92094f8027661c2b4d0b86ae8c1a0831dce147 100644
--- a/apps/ssi-abstraction/src/agent/anoncredsCredentials/anoncredsCredentials.service.ts
+++ b/apps/ssi-abstraction/src/agent/anoncredsCredentials/anoncredsCredentials.service.ts
@@ -1,5 +1,8 @@
 import type { TenantAgent } from '../agent.service.js';
-import type { CredentialExchangeRecord } from '@credo-ts/core';
+import type {
+  CredentialExchangeRecord,
+  CredentialStateChangedEvent,
+} from '@credo-ts/core';
 import type {
   EventAnonCredsCredentialOfferGetAll,
   EventAnonCredsCredentialOfferGetAllInput,
@@ -13,13 +16,19 @@ import type {
   EventAnonCredsCredentialsDeleteByIdInput,
   EventAnonCredsCredentialsGetAllInput,
   EventAnonCredsCredentialsGetByIdInput,
+  EventDidcommAnonCredsCredentialsAcceptOffer,
+  EventDidcommAnonCredsCredentialsAcceptOfferInput,
   EventDidcommAnonCredsCredentialsOffer,
   EventDidcommAnonCredsCredentialsOfferInput,
   EventDidcommAnonCredsCredentialsOfferToSelf,
   EventDidcommAnonCredsCredentialsOfferToSelfInput,
 } from '@ocm/shared';
 
-import { AutoAcceptCredential, CredentialState } from '@credo-ts/core';
+import {
+  AutoAcceptCredential,
+  CredentialEventTypes,
+  CredentialState,
+} from '@credo-ts/core';
 import { GenericRecord } from '@credo-ts/core/build/modules/generic-records/repository/GenericRecord.js';
 import { Injectable } from '@nestjs/common';
 import { logger } from '@ocm/shared';
@@ -138,6 +147,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,
@@ -193,7 +215,36 @@ export class AnonCredsCredentialsService {
 
       const revocationRegistryIndex = await this.getNextRevocationIdx(t);
 
-      return t.credentials.offerCredential({
+      const acceptOfferListener: Promise<CredentialExchangeRecord> =
+        new Promise((resolve) =>
+          t.events.on<CredentialStateChangedEvent>(
+            CredentialEventTypes.CredentialStateChanged,
+            async ({ payload: { credentialRecord } }) => {
+              const connection = connections.find(
+                (c) => c.id === credentialRecord.connectionId,
+              );
+
+              const withSelf = connection?.metadata.get<{ withSelf: boolean }>(
+                MetadataTokens.CONNECTION_METADATA_KEY,
+              );
+
+              const isWithSelf = withSelf?.withSelf ?? false;
+
+              if (
+                credentialRecord.state === CredentialState.OfferReceived &&
+                isWithSelf
+              ) {
+                resolve(
+                  await t.credentials.acceptOffer({
+                    credentialRecordId: credentialRecord.id,
+                  }),
+                );
+              }
+            },
+          ),
+        );
+
+      await t.credentials.offerCredential({
         protocolVersion: 'v2',
         autoAcceptCredential: AutoAcceptCredential.Always,
         connectionId: connection.id,
@@ -206,6 +257,8 @@ export class AnonCredsCredentialsService {
           },
         },
       });
+
+      return acceptOfferListener;
     });
   }
 
diff --git a/apps/ssi-abstraction/src/agent/connections/connections.service.ts b/apps/ssi-abstraction/src/agent/connections/connections.service.ts
index 1b6f8c4d84531aea50a7b4700a1cafb71b05815a..7ee1261a4e037a81b21b9f722ac33f4d8f3912b5 100644
--- a/apps/ssi-abstraction/src/agent/connections/connections.service.ts
+++ b/apps/ssi-abstraction/src/agent/connections/connections.service.ts
@@ -145,7 +145,16 @@ export class ConnectionsService {
       const outOfBandRecord = await t.oob.createInvitation();
       const invitation = outOfBandRecord.outOfBandInvitation;
 
-      void t.oob.receiveInvitation(invitation);
+      const { connectionRecord } = await t.oob.receiveInvitation(invitation);
+
+      if (connectionRecord) {
+        connectionRecord.metadata.set(MetadataTokens.CONNECTION_METADATA_KEY, {
+          trusted: true,
+          withSelf: true,
+        });
+        const connRepo = t.dependencyManager.resolve(ConnectionRepository);
+        await connRepo.update(t.context, connectionRecord);
+      }
 
       return new Promise((resolve) =>
         this.agent.events.on<ConnectionStateChangedEvent>(
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' },