diff --git a/agent-swagger.json b/agent-swagger.json
index 14412bef8a90088901894f7400cbba2ab4a066ab..1f69f9f096469f4f229325645aa7605f4e9d5f29 100644
--- a/agent-swagger.json
+++ b/agent-swagger.json
@@ -455,6 +455,89 @@
         }
       }
     },
+    "/api/v1/credentials/jsonld/offers": {
+      "post": {
+        "operationId": "RestController_offerJsonLdCredential",
+        "parameters": [],
+        "requestBody": {
+          "required": true,
+          "content": {
+            "application/json": {
+              "schema": {
+                "$ref": "#/components/schemas/OfferJsonCredentialRequests"
+              }
+            }
+          }
+        },
+        "responses": {
+          "201": {
+            "description": "",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/CredentialOfferResponseDto"
+                }
+              }
+            }
+          }
+        }
+      }
+    },
+    "/api/v1/jsonld/sign": {
+      "post": {
+        "operationId": "RestController_signJsonLdCredential",
+        "parameters": [],
+        "requestBody": {
+          "required": true,
+          "content": {
+            "application/json": {
+              "schema": {
+                "$ref": "#/components/schemas/SignJsonCredentialRequests"
+              }
+            }
+          }
+        },
+        "responses": {
+          "201": {
+            "description": "",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/W3cJsonLdVerifiableCredentialDto"
+                }
+              }
+            }
+          }
+        }
+      }
+    },
+    "/api/v1/jsonld/credentials/{cred_id}/prepare-verifiable-presentation": {
+      "post": {
+        "operationId": "RestController_signJsonLdPresentationByCredId",
+        "parameters": [
+          {
+            "name": "cred_id",
+            "required": true,
+            "in": "path",
+            "schema": {
+              "type": "string"
+            }
+          }
+        ],
+        "responses": {
+          "201": {
+            "description": "",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/W3cJsonLdVerifiablePresentationDto"
+                }
+              }
+            }
+          }
+        }
+      }
+    },
     "/api/v1/credentials": {
       "get": {
         "operationId": "RestController_fetchCredentials",
@@ -1414,6 +1497,175 @@
           "credentialRecord"
         ]
       },
+      "W3cCredentialStatusDto": {
+        "type": "object",
+        "properties": {
+          "id": {
+            "type": "string"
+          },
+          "type": {
+            "type": "string"
+          }
+        },
+        "required": [
+          "id",
+          "type"
+        ]
+      },
+      "W3cCredentialDto": {
+        "type": "object",
+        "properties": {
+          "context": {
+            "type": "array",
+            "items": {
+              "type": "object"
+            }
+          },
+          "id": {
+            "type": "string"
+          },
+          "type": {
+            "type": "array",
+            "items": {
+              "type": "string"
+            }
+          },
+          "issuer": {
+            "type": "object"
+          },
+          "issuanceDate": {
+            "type": "string"
+          },
+          "expirationDate": {
+            "type": "string"
+          },
+          "credentialSubject": {
+            "type": "object"
+          },
+          "credentialSchema": {
+            "type": "object"
+          },
+          "credentialStatus": {
+            "$ref": "#/components/schemas/W3cCredentialStatusDto"
+          }
+        },
+        "required": [
+          "context",
+          "type",
+          "issuer",
+          "issuanceDate",
+          "credentialSubject"
+        ]
+      },
+      "OfferJsonCredentialRequests": {
+        "type": "object",
+        "properties": {
+          "connectionId": {
+            "type": "string"
+          },
+          "doc": {
+            "$ref": "#/components/schemas/W3cCredentialDto"
+          }
+        },
+        "required": [
+          "doc"
+        ]
+      },
+      "SignJsonCredentialRequests": {
+        "type": "object",
+        "properties": {
+          "doc": {
+            "$ref": "#/components/schemas/W3cCredentialDto"
+          }
+        },
+        "required": [
+          "doc"
+        ]
+      },
+      "W3cJsonLdVerifiableCredentialDto": {
+        "type": "object",
+        "properties": {
+          "context": {
+            "type": "array",
+            "items": {
+              "type": "object"
+            }
+          },
+          "id": {
+            "type": "string"
+          },
+          "type": {
+            "type": "array",
+            "items": {
+              "type": "string"
+            }
+          },
+          "issuer": {
+            "type": "object"
+          },
+          "issuanceDate": {
+            "type": "string"
+          },
+          "expirationDate": {
+            "type": "string"
+          },
+          "credentialSubject": {
+            "type": "object"
+          },
+          "credentialSchema": {
+            "type": "object"
+          },
+          "credentialStatus": {
+            "$ref": "#/components/schemas/W3cCredentialStatusDto"
+          },
+          "proof": {
+            "type": "object"
+          }
+        },
+        "required": [
+          "context",
+          "type",
+          "issuer",
+          "issuanceDate",
+          "credentialSubject",
+          "proof"
+        ]
+      },
+      "W3cJsonLdVerifiablePresentationDto": {
+        "type": "object",
+        "properties": {
+          "proof": {
+            "type": "object"
+          },
+          "context": {
+            "type": "array",
+            "items": {
+              "type": "object"
+            }
+          },
+          "id": {
+            "type": "string"
+          },
+          "type": {
+            "type": "array",
+            "items": {
+              "type": "string"
+            }
+          },
+          "holder": {
+            "type": "object"
+          },
+          "verifiableCredential": {
+            "type": "object"
+          }
+        },
+        "required": [
+          "proof",
+          "context",
+          "type",
+          "verifiableCredential"
+        ]
+      },
       "CredentialFormatDataDto": {
         "type": "object",
         "properties": {
@@ -1440,6 +1692,9 @@
           },
           "anoncredsCredential": {
             "type": "object"
+          },
+          "all": {
+            "type": "object"
           }
         }
       },
diff --git a/libs/askar/src/agent.utils.ts b/libs/askar/src/agent.utils.ts
index 2bd89628296e027edbe67c245d5eda792fe50157..84444829e6494a98509b1c16b9a736732008f060 100644
--- a/libs/askar/src/agent.utils.ts
+++ b/libs/askar/src/agent.utils.ts
@@ -5,30 +5,31 @@ import {
   BaseEvent,
   ConnectionsModule,
   ConnectionStateChangedEvent,
+  CredentialEventTypes,
   CredentialsModule,
+  CredentialState,
+  CredentialStateChangedEvent,
+  DidDocument,
   DidExchangeRole,
   DidsModule,
   EncryptedMessage,
+  JsonTransformer,
   Key,
   KeyDidResolver,
   KeyType,
+  OutOfBandState,
   PeerDidResolver,
   ProofEventTypes,
+  ProofExchangeRecord,
   ProofsModule,
   ProofState,
   ProofStateChangedEvent,
   TypedArrayEncoder,
   V2CredentialProtocol,
   V2ProofProtocol,
+  W3cCredentialsModule,
   WalletError,
   WalletKeyExistsError,
-  OutOfBandState,
-  CredentialStateChangedEvent,
-  CredentialEventTypes,
-  CredentialState,
-  ProofExchangeRecord,
-  JsonTransformer,
-  DidDocument,
   WebDidResolver,
   JwkDidResolver,
   TrustPingResponseReceivedEvent,
@@ -74,6 +75,7 @@ export type SubjectMessage = {
 };
 import { Request, Response, Express } from "express";
 import url from "url";
+import { JsonLdCredentialFormatService } from "./credo/JsonLdCredentialFormatService";
 
 export const importDidsToWallet = async (
   agent: Agent,
@@ -216,7 +218,10 @@ export const getAskarAnonCredsIndyModules = (networks: any) => {
       autoAcceptCredentials: AutoAcceptCredential.ContentApproved,
       credentialProtocols: [
         new V2CredentialProtocol({
-          credentialFormats: [new AnonCredsCredentialFormatService()],
+          credentialFormats: [
+            new AnonCredsCredentialFormatService(),
+            new JsonLdCredentialFormatService(),
+          ],
         }),
       ],
     }),
@@ -255,6 +260,7 @@ export const getAskarAnonCredsIndyModules = (networks: any) => {
     askar: new AskarModule({
       ariesAskar,
     }),
+    w3c: new W3cCredentialsModule(),
   } as const;
 };
 
diff --git a/libs/askar/src/askar-rest/rest.controller.ts b/libs/askar/src/askar-rest/rest.controller.ts
index adbc7697379bbf79965709327459c5b525b690a2..a9340e09baf02d09bd9c42465683d3983fed3c3d 100644
--- a/libs/askar/src/askar-rest/rest.controller.ts
+++ b/libs/askar/src/askar-rest/rest.controller.ts
@@ -26,6 +26,8 @@ import {
   CreateInvitationRequestDto,
   InvitationFilterDto,
   AcceptInvitationRequestDto,
+  OfferJsonCredentialRequests,
+  SignJsonCredentialRequests,
   DidRecordDto,
 } from "@ocm-engine/dtos";
 import { AllExceptionsHandler } from "./exception.handler";
@@ -135,6 +137,23 @@ export class RestController {
     return this.agentService.offerCredential(dto);
   }
 
+  @Post("/credentials/jsonld/offers")
+  async offerJsonLdCredential(@Body() data: OfferJsonCredentialRequests) {
+    return this.agentService.offerJsonLdCredential(data.connectionId, data.doc);
+  }
+
+  @Post("/jsonld/sign")
+  async signJsonLdCredential(@Body() data: SignJsonCredentialRequests) {
+    return this.agentService.signJsonLdCredential(data.doc);
+  }
+
+  @Post("/jsonld/credentials/:cred_id/prepare-verifiable-presentation")
+  async signJsonLdPresentationByCredId(@Param("cred_id") credentialId: string) {
+    return this.agentService.prepareVerifiablePresentationByJsonLdCredId(
+      credentialId,
+    );
+  }
+
   @Get("/credentials")
   async fetchCredentials(@Query() credentialFilterDto: CredentialFilterDto) {
     return this.agentService.fetchCredentials(credentialFilterDto);
diff --git a/libs/askar/src/askar/agent.service.ts b/libs/askar/src/askar/agent.service.ts
index 9439fbba76dce855bf87829ce35bb8c1156a3acf..3fb35aa71487ad32c9c5ef78f68f36c317507c77 100644
--- a/libs/askar/src/askar/agent.service.ts
+++ b/libs/askar/src/askar/agent.service.ts
@@ -1,4 +1,4 @@
-import { Injectable } from "@nestjs/common";
+import { Injectable, Logger } from "@nestjs/common";
 import { AskarService } from "./askar.service";
 import {
   ConnectionRecordDto,
@@ -28,19 +28,30 @@ import {
   CreateInvitationRequestDto,
   InvitationFilterDto,
   DidRecordDto,
+  OcmError,
+  W3cCredentialDto,
   BaseRecordDto,
+  W3cJsonLdVerifiableCredentialDto,
+  W3cJsonLdVerifiablePresentationDto,
 } from "@ocm-engine/dtos";
 import {
   AutoAcceptCredential,
   BasicMessageRecord,
   BasicMessageRole,
+  ClaimFormat,
   ConnectionRecord,
   CredentialExchangeRecord,
+  JsonTransformer,
   CredentialState,
   ProofState,
   Query,
   ProofExchangeRecord,
   OutOfBandRecord,
+  W3cCredential,
+  W3cCredentialService,
+  DidRecord,
+  JsonCredential,
+  W3cJsonLdVerifiableCredential,
 } from "@aries-framework/core";
 import { AnonCredsRequestedAttribute } from "@aries-framework/anoncreds";
 import { uuid } from "@aries-framework/core/build/utils/uuid";
@@ -51,6 +62,7 @@ import {
 
 @Injectable()
 export class AgentService {
+  private readonly logger = new Logger(AgentService.name);
   constructor(private readonly askar: AskarService) {}
 
   createInvitation = async (
@@ -391,10 +403,238 @@ export class AgentService {
     return response;
   };
 
+  signJsonLdCredential = async (
+    credToSign: W3cCredentialDto,
+  ): Promise<W3cJsonLdVerifiableCredentialDto> => {
+    this.logger.log("Sign json ld credentials");
+
+    const didRecord = await this.getFirstDidWebRecord();
+    const verificationMethodList =
+      didRecord.didDocument?.verificationMethod || [];
+    if (!verificationMethodList.length) {
+      throw new EntityNotFoundError(
+        "DidDocument does not exists or contains no verification methods",
+      );
+    }
+
+    const verificationMethod = verificationMethodList[0];
+
+    const w3cServ =
+      this.askar.agent.context.dependencyManager.resolve(W3cCredentialService);
+
+    credToSign.id = didRecord.did + "?uuid=" + uuid();
+    if (credToSign.credentialSubject) {
+      // @ts-ignore
+      credToSign.credentialSubject.id = credToSign.id;
+    }
+    credToSign.issuer = didRecord.did;
+    credToSign.issuanceDate = new Date().toISOString();
+    let credential: W3cCredential;
+    try {
+      credential = JsonTransformer.fromJSON(credToSign, W3cCredential);
+    } catch (e) {
+      this.logger.log("Incorrect request parameter", e);
+      throw new OcmError(
+        "Invalid JSON-LD data format. Please ensure that your JSON-LD contains the following properties: @context, id, type, issuer, issuanceDate, expirationDate, and credentialSubject.",
+      );
+    }
+
+    const vc = await w3cServ.signCredential(this.askar.agent.context, {
+      format: ClaimFormat.LdpVc,
+      credential,
+      proofType: "Ed25519Signature2018",
+      verificationMethod: verificationMethod.id,
+    });
+
+    // @ts-ignore
+    const jsonVC = vc.toJson() as W3cJsonLdVerifiableCredentialDto;
+    this.logger.debug(JSON.stringify(jsonVC, null, 2));
+
+    return jsonVC;
+  };
+
+  prepareVerifiablePresentationByJsonLdCredId = async (
+    credentialRecordId: string,
+  ): Promise<W3cJsonLdVerifiablePresentationDto> => {
+    const didRecord = await this.getFirstDidWebRecord();
+    const verificationMethodList =
+      didRecord.didDocument?.verificationMethod || [];
+    if (!verificationMethodList.length) {
+      throw new EntityNotFoundError(
+        "DidDocument does not exists or contains no verification methods",
+      );
+    }
+
+    const verificationMethod = verificationMethodList[0];
+
+    const credFormatData = await this.askar.agent.credentials.getFormatData(
+      credentialRecordId,
+    );
+    if (!credFormatData.credential?.jsonld) {
+      throw new OcmError(
+        "The JSON-LD credential is either not in your wallet, pending approval, or not in the JSON-LD format.",
+      );
+    }
+
+    const jsonLd = credFormatData.credential.jsonld;
+    const vc = JsonTransformer.fromJSON(jsonLd, W3cJsonLdVerifiableCredential);
+
+    const w3cServ =
+      this.askar.agent.context.dependencyManager.resolve(W3cCredentialService);
+    const presentation = await w3cServ.createPresentation({
+      credentials: [vc],
+      id: didRecord.did + "?uuid=" + uuid(),
+    });
+
+    const vp = await w3cServ.signPresentation(this.askar.agent.context, {
+      format: ClaimFormat.LdpVp,
+      presentation,
+      proofPurpose: null,
+      proofType: "Ed25519Signature2018",
+      challenge: uuid(),
+      verificationMethod: verificationMethod.id,
+    });
+
+    // @ts-ignore
+    const jsonVP = vp.toJson() as W3cJsonLdVerifiablePresentationDto;
+    this.logger.debug(JSON.stringify(jsonVP, null, 2));
+
+    return jsonVP;
+  };
+
+  offerJsonLdCredential = async (
+    connectionId: string | undefined,
+    credToSign: W3cCredentialDto,
+  ): Promise<CredentialOfferResponseDto> => {
+    this.logger.log("offerJsonLdCredential", connectionId);
+
+    const didRecord = await this.getFirstDidWebRecord();
+    const verificationMethodList =
+      didRecord.didDocument?.verificationMethod || [];
+    if (!verificationMethodList.length) {
+      throw new EntityNotFoundError(
+        "DidDocument does not exists or contains no verification methods",
+      );
+    }
+
+    const verificationMethod = verificationMethodList[0];
+
+    const w3cServ =
+      this.askar.agent.context.dependencyManager.resolve(W3cCredentialService);
+
+    credToSign.id = didRecord.did + "?uuid=" + uuid();
+    if (credToSign.credentialSubject) {
+      // @ts-ignore
+      credToSign.credentialSubject.id = credToSign.id;
+    }
+    credToSign.issuer = didRecord.did;
+    credToSign.issuanceDate = new Date().toISOString();
+    let credential: W3cCredential;
+    try {
+      credential = JsonTransformer.fromJSON(credToSign, W3cCredential);
+    } catch (e) {
+      this.logger.log("Incorrect request parameter", e);
+      throw new OcmError(
+        "Invalid JSON-LD data format. Please ensure that your JSON-LD contains the following properties: @context, id, type, issuer, issuanceDate, expirationDate, and credentialSubject.",
+      );
+    }
+
+    const vc = await w3cServ.signCredential(this.askar.agent.context, {
+      format: ClaimFormat.LdpVc,
+      credential,
+      proofType: "Ed25519Signature2018",
+      verificationMethod: verificationMethod.id,
+    });
+
+    // @ts-ignore
+    const jsonVC = vc.toJson() as JsonCredential;
+
+    if (!connectionId) {
+      // create connection less credential
+      const { credentialRecord, message } =
+        await this.askar.agent.credentials.createOffer({
+          protocolVersion: "v2",
+          credentialFormats: {
+            jsonld: {
+              credential: jsonVC,
+              options: {
+                proofType: "Ed25519Signature2018",
+                proofPurpose: "assertionMethod",
+              },
+            },
+          },
+          autoAcceptCredential: AutoAcceptCredential.ContentApproved,
+        });
+
+      credentialRecord.setTag("xRole", "issuer");
+      await this.askar.agent.credentials.update(credentialRecord);
+
+      const outOfBandRecord = await this.askar.agent.oob.createInvitation({
+        messages: [message],
+        handshake: false,
+      });
+
+      const credentialUrl = outOfBandRecord.outOfBandInvitation.toUrl({
+        domain: this.askar.agentConfig.agentPeerAddress,
+      });
+
+      const shortCredentialUrl = `${this.askar.agentConfig.agentPeerAddress}/invitations/${outOfBandRecord.outOfBandInvitation.id}`;
+
+      const dto = new CredentialRecordDto();
+      dto.id = credentialRecord.id;
+      dto.state = credentialRecord.state;
+      dto.connectionId = credentialRecord.connectionId;
+      dto.attributes = credentialRecord.credentialAttributes;
+      dto.createdAt = credentialRecord.createdAt;
+      dto.tags = credentialRecord.getTags();
+
+      return {
+        credentialUrl: credentialUrl,
+        shortCredentialUrl: shortCredentialUrl,
+        credentialRecord: dto,
+      };
+    }
+
+    const credentialExchangeRecord =
+      await this.askar.agent.credentials.offerCredential({
+        connectionId: connectionId,
+        protocolVersion: "v2",
+        credentialFormats: {
+          jsonld: {
+            credential: jsonVC,
+            options: {
+              proofType: "Ed25519Signature2018",
+              proofPurpose: "assertionMethod",
+            },
+          },
+        },
+        autoAcceptCredential: AutoAcceptCredential.ContentApproved,
+      });
+
+    this.logger.log(credentialExchangeRecord);
+
+    credentialExchangeRecord.setTag("xRole", "issuer");
+    await this.askar.agent.credentials.update(credentialExchangeRecord);
+
+    const dto = new CredentialRecordDto();
+    dto.id = credentialExchangeRecord.id;
+    dto.state = credentialExchangeRecord.state;
+    dto.connectionId = credentialExchangeRecord.connectionId;
+    dto.attributes = credentialExchangeRecord.credentialAttributes;
+    dto.createdAt = credentialExchangeRecord.createdAt;
+    dto.tags = credentialExchangeRecord.getTags();
+
+    return {
+      credentialUrl: null,
+      shortCredentialUrl: null,
+      credentialRecord: dto,
+    };
+  };
+
   offerCredential = async (
     offerCredentialDto: OfferCredentialRequestDto,
   ): Promise<CredentialOfferResponseDto> => {
-    console.log(
+    this.logger.log(
       "Incoming request",
       JSON.stringify(offerCredentialDto, null, 2),
     );
@@ -636,13 +876,15 @@ export class AgentService {
     dto.anoncredsRequest = formatData.request?.anoncreds;
     dto.anoncredsCredential = formatData.credential?.anoncreds;
 
+    dto.all = formatData;
+
     return dto;
   };
 
   requestProof = async (
     requestProofDto: RequestProofDto,
   ): Promise<RequestProofResponseDto> => {
-    console.log(JSON.stringify(requestProofDto, null, 2));
+    this.logger.log(JSON.stringify(requestProofDto, null, 2));
     const requestedAttributes: Record<string, AnonCredsRequestedAttribute> = {};
 
     for (const attr of requestProofDto.attributes) {
@@ -658,7 +900,7 @@ export class AgentService {
     }
 
     if (!requestProofDto.connectionId) {
-      console.log("connection Id not detected, creating oob proof");
+      this.logger.log("connection Id not detected, creating oob proof");
       const { proofRecord, message } =
         await this.askar.agent.proofs.createRequest({
           protocolVersion: "v2",
@@ -699,7 +941,7 @@ export class AgentService {
       };
     }
 
-    console.log(`${requestProofDto.connectionId} detected, issuing proof`);
+    this.logger.log(`${requestProofDto.connectionId} detected, issuing proof`);
 
     const exchangeRecord = await this.askar.agent.proofs.requestProof({
       protocolVersion: "v2",
@@ -883,20 +1125,20 @@ export class AgentService {
   acceptConnectionProof = async (
     proofRecordId: string,
   ): Promise<ProofRecordDto> => {
-    console.log(`accepting proof request for ${proofRecordId}`);
+    this.logger.log(`accepting proof request for ${proofRecordId}`);
     const requestedCredentials =
       await this.askar.agent.proofs.selectCredentialsForRequest({
         proofRecordId,
       });
 
-    console.log(JSON.stringify(requestedCredentials, null, 2));
+    this.logger.log(JSON.stringify(requestedCredentials, null, 2));
 
     const proof = await this.askar.agent.proofs.acceptRequest({
       proofRecordId,
       proofFormats: requestedCredentials.proofFormats,
     });
 
-    console.log(JSON.stringify(proof, null, 2));
+    this.logger.log(JSON.stringify(proof, null, 2));
 
     const response = new ProofRecordDto();
     response.id = proof.id;
@@ -1054,4 +1296,14 @@ export class AgentService {
 
     return response;
   };
+
+  private getFirstDidWebRecord = async (): Promise<DidRecord> => {
+    const didWebs = await this.askar.agent.dids.getCreatedDids({
+      method: "web",
+    });
+    if (!didWebs.length) {
+      throw new EntityNotFoundError("Agent does not have did:web");
+    }
+    return didWebs[0];
+  };
 }
diff --git a/libs/askar/src/credo/JsonLdCredentialFormatService.ts b/libs/askar/src/credo/JsonLdCredentialFormatService.ts
new file mode 100644
index 0000000000000000000000000000000000000000..2b35f6c7fcb096796cf6347ce1efb6dd7a2da19c
--- /dev/null
+++ b/libs/askar/src/credo/JsonLdCredentialFormatService.ts
@@ -0,0 +1,582 @@
+import {
+  JsonLdCredentialFormat,
+  JsonCredential,
+  JsonLdFormatDataCredentialDetail,
+  JsonLdFormatDataVerifiableCredential,
+  AgentContext,
+  CredentialFormatService,
+  Attachment,
+  AttachmentData,
+  AriesFrameworkError,
+  JsonEncoder,
+  JsonTransformer,
+  findVerificationMethodByKeyType,
+  DidResolverService,
+  ClaimFormat,
+  W3cCredential,
+  W3cCredentialService,
+  W3cJsonLdVerifiableCredential,
+  CredentialFormatSpec,
+  JsonLdCredentialDetail,
+} from "@aries-framework/core";
+import type {
+  CredentialFormatAcceptOfferOptions,
+  CredentialFormatAcceptProposalOptions,
+  CredentialFormatAcceptRequestOptions,
+  CredentialFormatAutoRespondOfferOptions,
+  CredentialFormatAutoRespondProposalOptions,
+  CredentialFormatAutoRespondRequestOptions,
+  CredentialFormatCreateOfferOptions,
+  CredentialFormatCreateOfferReturn,
+  CredentialFormatCreateProposalOptions,
+  CredentialFormatCreateProposalReturn,
+  CredentialFormatCreateRequestOptions,
+  CredentialFormatCreateReturn,
+  CredentialFormatProcessCredentialOptions,
+  CredentialFormatProcessOptions,
+  CredentialFormatAutoRespondCredentialOptions,
+} from "@aries-framework/core";
+import { areObjectsEqual } from "@aries-framework/core/build/utils";
+import { W3cJsonLdCredentialService } from "@aries-framework/core/build/modules/vc/data-integrity/W3cJsonLdCredentialService";
+
+const JSONLD_VC_DETAIL = "aries/ld-proof-vc-detail@v1.0";
+const JSONLD_VC = "aries/ld-proof-vc@v1.0";
+
+export class JsonLdCredentialFormatService
+  implements CredentialFormatService<JsonLdCredentialFormat>
+{
+  public readonly formatKey = "jsonld" as const;
+  public readonly credentialRecordType = "w3c" as const;
+
+  /**
+   * Create a {@link AttachmentFormats} object dependent on the message type.
+   *
+   * @param options The object containing all the options for the proposed credential
+   * @returns object containing associated attachment, formats and filtersAttach elements
+   *
+   */
+  public async createProposal(
+    agentContext: AgentContext,
+    {
+      credentialFormats,
+    }: CredentialFormatCreateProposalOptions<JsonLdCredentialFormat>,
+  ): Promise<CredentialFormatCreateProposalReturn> {
+    const format = new CredentialFormatSpec({
+      format: JSONLD_VC_DETAIL,
+    });
+
+    const jsonLdFormat = credentialFormats.jsonld;
+    if (!jsonLdFormat) {
+      throw new AriesFrameworkError("Missing jsonld payload in createProposal");
+    }
+
+    // this does the validation
+    JsonTransformer.fromJSON(jsonLdFormat.credential, JsonLdCredentialDetail);
+
+    // jsonLdFormat is now of type JsonLdFormatDataCredentialDetail
+    const attachment = this.getFormatData(jsonLdFormat, format.attachmentId);
+    return { format, attachment };
+  }
+
+  /**
+   * Method called on reception of a propose credential message
+   * @param options the options needed to accept the proposal
+   */
+  public async processProposal(
+    agentContext: AgentContext,
+    { attachment }: CredentialFormatProcessOptions,
+  ): Promise<void> {
+    const credProposalJson =
+      attachment.getDataAsJson<JsonLdFormatDataCredentialDetail>();
+
+    if (!credProposalJson) {
+      throw new AriesFrameworkError(
+        "Missing jsonld credential proposal data payload",
+      );
+    }
+
+    // validation is done in here
+    JsonTransformer.fromJSON(credProposalJson, JsonLdCredentialDetail);
+  }
+
+  public async acceptProposal(
+    agentContext: AgentContext,
+    {
+      attachmentId,
+      proposalAttachment,
+    }: CredentialFormatAcceptProposalOptions<JsonLdCredentialFormat>,
+  ): Promise<CredentialFormatCreateOfferReturn> {
+    // if the offer has an attachment Id use that, otherwise the generated id of the formats object
+    const format = new CredentialFormatSpec({
+      attachmentId,
+      format: JSONLD_VC_DETAIL,
+    });
+
+    const credentialProposal =
+      proposalAttachment.getDataAsJson<JsonLdFormatDataCredentialDetail>();
+    JsonTransformer.fromJSON(credentialProposal, JsonLdCredentialDetail);
+
+    const offerData = credentialProposal;
+
+    const attachment = this.getFormatData(offerData, format.attachmentId);
+
+    return { format, attachment };
+  }
+
+  /**
+   * Create a {@link AttachmentFormats} object dependent on the message type.
+   *
+   * @param options The object containing all the options for the credential offer
+   * @returns object containing associated attachment, formats and offersAttach elements
+   *
+   */
+  public async createOffer(
+    agentContext: AgentContext,
+    {
+      credentialFormats,
+      attachmentId,
+    }: CredentialFormatCreateOfferOptions<JsonLdCredentialFormat>,
+  ): Promise<CredentialFormatCreateOfferReturn> {
+    // if the offer has an attachment Id use that, otherwise the generated id of the formats object
+    const format = new CredentialFormatSpec({
+      attachmentId,
+      format: JSONLD_VC_DETAIL,
+    });
+
+    const jsonLdFormat = credentialFormats?.jsonld;
+    if (!jsonLdFormat) {
+      throw new AriesFrameworkError("Missing jsonld payload in createOffer");
+    }
+
+    // validate
+    JsonTransformer.fromJSON(jsonLdFormat.credential, JsonLdCredentialDetail);
+
+    const attachment = this.getFormatData(jsonLdFormat, format.attachmentId);
+
+    return { format, attachment };
+  }
+
+  public async processOffer(
+    agentContext: AgentContext,
+    { attachment }: CredentialFormatProcessOptions,
+  ) {
+    const credentialOfferJson =
+      attachment.getDataAsJson<JsonLdFormatDataCredentialDetail>();
+
+    if (!credentialOfferJson) {
+      throw new AriesFrameworkError(
+        "Missing jsonld credential offer data payload",
+      );
+    }
+
+    JsonTransformer.fromJSON(credentialOfferJson, JsonLdCredentialDetail);
+  }
+
+  public async acceptOffer(
+    agentContext: AgentContext,
+    {
+      attachmentId,
+      offerAttachment,
+    }: CredentialFormatAcceptOfferOptions<JsonLdCredentialFormat>,
+  ): Promise<CredentialFormatCreateReturn> {
+    const credentialOffer =
+      offerAttachment.getDataAsJson<JsonLdFormatDataCredentialDetail>();
+
+    // validate
+    JsonTransformer.fromJSON(credentialOffer, JsonLdCredentialDetail);
+
+    const format = new CredentialFormatSpec({
+      attachmentId,
+      format: JSONLD_VC_DETAIL,
+    });
+
+    const attachment = this.getFormatData(credentialOffer, format.attachmentId);
+    return { format, attachment };
+  }
+
+  /**
+   * Create a credential attachment format for a credential request.
+   *
+   * @param options The object containing all the options for the credential request is derived
+   * @returns object containing associated attachment, formats and requestAttach elements
+   *
+   */
+  public async createRequest(
+    agentContext: AgentContext,
+    {
+      credentialFormats,
+    }: CredentialFormatCreateRequestOptions<JsonLdCredentialFormat>,
+  ): Promise<CredentialFormatCreateReturn> {
+    const jsonLdFormat = credentialFormats?.jsonld;
+
+    const format = new CredentialFormatSpec({
+      format: JSONLD_VC_DETAIL,
+    });
+
+    if (!jsonLdFormat) {
+      throw new AriesFrameworkError("Missing jsonld payload in createRequest");
+    }
+
+    // this does the validation
+    JsonTransformer.fromJSON(jsonLdFormat.credential, JsonLdCredentialDetail);
+
+    const attachment = this.getFormatData(jsonLdFormat, format.attachmentId);
+
+    return { format, attachment };
+  }
+
+  public async processRequest(
+    agentContext: AgentContext,
+    { attachment }: CredentialFormatProcessOptions,
+  ): Promise<void> {
+    const requestJson =
+      attachment.getDataAsJson<JsonLdFormatDataCredentialDetail>();
+
+    if (!requestJson) {
+      throw new AriesFrameworkError(
+        "Missing jsonld credential request data payload",
+      );
+    }
+
+    // validate
+    JsonTransformer.fromJSON(requestJson, JsonLdCredentialDetail);
+  }
+
+  public async acceptRequest(
+    agentContext: AgentContext,
+    {
+      credentialFormats,
+      attachmentId,
+      requestAttachment,
+    }: CredentialFormatAcceptRequestOptions<JsonLdCredentialFormat>,
+  ): Promise<CredentialFormatCreateReturn> {
+    const w3cJsonLdCredentialService = agentContext.dependencyManager.resolve(
+      W3cJsonLdCredentialService,
+    );
+
+    // sign credential here. credential to be signed is received as the request attachment
+    // (attachment in the request message from holder to issuer)
+    const credentialRequest =
+      requestAttachment.getDataAsJson<JsonLdFormatDataCredentialDetail>();
+
+    const verificationMethod =
+      credentialFormats?.jsonld?.verificationMethod ??
+      (await this.deriveVerificationMethod(
+        agentContext,
+        credentialRequest.credential,
+        credentialRequest,
+      ));
+
+    if (!verificationMethod) {
+      throw new AriesFrameworkError(
+        "Missing verification method in credential data",
+      );
+    }
+    const format = new CredentialFormatSpec({
+      attachmentId,
+      format: JSONLD_VC,
+    });
+
+    const options = credentialRequest.options;
+
+    // Get a list of fields found in the options that are not supported at the moment
+    const unsupportedFields = [
+      "challenge",
+      "domain",
+      "credentialStatus",
+      "created",
+    ] as const;
+    const foundFields = unsupportedFields.filter(
+      (field) => options[field] !== undefined,
+    );
+
+    if (foundFields.length > 0) {
+      throw new AriesFrameworkError(
+        `Some fields are not currently supported in credential options: ${foundFields.join(
+          ", ",
+        )}`,
+      );
+    }
+
+    const credential = JsonTransformer.fromJSON(
+      credentialRequest.credential,
+      W3cCredential,
+    );
+
+    const verifiableCredential =
+      await w3cJsonLdCredentialService.signCredential(agentContext, {
+        format: ClaimFormat.LdpVc,
+        credential,
+        proofType: credentialRequest.options.proofType,
+        verificationMethod: verificationMethod,
+      });
+
+    const attachment = this.getFormatData(
+      JsonTransformer.toJSON(verifiableCredential),
+      format.attachmentId,
+    );
+    return { format, attachment };
+  }
+
+  /**
+   * Derive a verification method using the issuer from the given verifiable credential
+   * @param credentialAsJson the verifiable credential we want to sign
+   * @return the verification method derived from this credential and its associated issuer did, keys etc.
+   */
+  private async deriveVerificationMethod(
+    agentContext: AgentContext,
+    credentialAsJson: JsonCredential,
+    credentialRequest: JsonLdFormatDataCredentialDetail,
+  ): Promise<string> {
+    const didResolver =
+      agentContext.dependencyManager.resolve(DidResolverService);
+    const w3cJsonLdCredentialService = agentContext.dependencyManager.resolve(
+      W3cJsonLdCredentialService,
+    );
+
+    const credential = JsonTransformer.fromJSON(
+      credentialAsJson,
+      W3cCredential,
+    );
+
+    // extract issuer from vc (can be string or Issuer)
+    let issuerDid = credential.issuer;
+
+    if (typeof issuerDid !== "string") {
+      issuerDid = issuerDid.id;
+    }
+    // this will throw an error if the issuer did is invalid
+    const issuerDidDocument = await didResolver.resolveDidDocument(
+      agentContext,
+      issuerDid,
+    );
+
+    // find first key which matches proof type
+    const proofType = credentialRequest.options.proofType;
+
+    // actually gets the key type(s)
+    const keyType =
+      w3cJsonLdCredentialService.getVerificationMethodTypesByProofType(
+        proofType,
+      );
+
+    if (!keyType || keyType.length === 0) {
+      throw new AriesFrameworkError(
+        `No Key Type found for proofType ${proofType}`,
+      );
+    }
+
+    const verificationMethod = await findVerificationMethodByKeyType(
+      keyType[0],
+      issuerDidDocument,
+    );
+    if (!verificationMethod) {
+      throw new AriesFrameworkError(
+        `Missing verification method for key type ${keyType}`,
+      );
+    }
+
+    return verificationMethod.id;
+  }
+  /**
+   * Processes an incoming credential - retrieve metadata, retrieve payload and store it in the Indy wallet
+   * @param options the issue credential message wrapped inside this object
+   * @param credentialRecord the credential exchange record for this credential
+   */
+  public async processCredential(
+    agentContext: AgentContext,
+    {
+      credentialRecord,
+      attachment,
+      requestAttachment,
+    }: CredentialFormatProcessCredentialOptions,
+  ): Promise<void> {
+    const w3cCredentialService =
+      agentContext.dependencyManager.resolve(W3cCredentialService);
+
+    const credentialAsJson = attachment.getDataAsJson();
+    const credential = JsonTransformer.fromJSON(
+      credentialAsJson,
+      W3cJsonLdVerifiableCredential,
+    );
+    const requestAsJson =
+      requestAttachment.getDataAsJson<JsonLdFormatDataCredentialDetail>();
+
+    // Verify the credential request matches the credential
+    this.verifyReceivedCredentialMatchesRequest(credential, requestAsJson);
+
+    // verify signatures of the credential
+    const result = await w3cCredentialService.verifyCredential(agentContext, {
+      credential,
+    });
+    if (result && !result.isValid) {
+      throw new AriesFrameworkError(
+        `Failed to validate credential, error = ${result.error}`,
+      );
+    }
+
+    const verifiableCredential = await w3cCredentialService.storeCredential(
+      agentContext,
+      {
+        credential,
+      },
+    );
+
+    credentialRecord.credentials.push({
+      credentialRecordType: this.credentialRecordType,
+      credentialRecordId: verifiableCredential.id,
+    });
+  }
+
+  private verifyReceivedCredentialMatchesRequest(
+    credential: W3cJsonLdVerifiableCredential,
+    request: JsonLdFormatDataCredentialDetail,
+  ): void {
+    const jsonCredential = JsonTransformer.toJSON(credential);
+    delete jsonCredential["proof"];
+
+    const credentialProof = Array.isArray(credential.proof)
+      ? credential.proof[credential.proof.length - 1]
+      : credential.proof;
+
+    if (
+      request.options.created &&
+      credentialProof.created !== request.options.created
+    ) {
+      throw new AriesFrameworkError(
+        "Received credential proof created does not match created from credential request",
+      );
+    }
+
+    if (credentialProof.domain !== request.options.domain) {
+      throw new AriesFrameworkError(
+        "Received credential proof domain does not match domain from credential request",
+      );
+    }
+
+    if (credentialProof.challenge !== request.options.challenge) {
+      throw new AriesFrameworkError(
+        "Received credential proof challenge does not match challenge from credential request",
+      );
+    }
+
+    if (credentialProof.type !== request.options.proofType) {
+      throw new AriesFrameworkError(
+        "Received credential proof type does not match proof type from credential request",
+      );
+    }
+
+    if (credentialProof.proofPurpose !== request.options.proofPurpose) {
+      throw new AriesFrameworkError(
+        "Received credential proof purpose does not match proof purpose from credential request",
+      );
+    }
+
+    // Check whether the received credential (minus the proof) matches the credential request
+    const requestJsonCredential = JsonTransformer.toJSON(request.credential);
+    delete requestJsonCredential["proof"];
+    if (!areObjectsEqual(jsonCredential, requestJsonCredential)) {
+      throw new AriesFrameworkError(
+        "Received credential does not match credential request",
+      );
+    }
+
+    // TODO: add check for the credentialStatus once this is supported in Credo
+  }
+
+  public supportsFormat(format: string): boolean {
+    const supportedFormats = [JSONLD_VC_DETAIL, JSONLD_VC];
+
+    return supportedFormats.includes(format);
+  }
+
+  public async deleteCredentialById(): Promise<void> {
+    throw new Error("Not implemented.");
+  }
+
+  public areCredentialsEqual = (
+    message1: Attachment,
+    message2: Attachment,
+  ): boolean => {
+    const obj1 = message1.getDataAsJson();
+    const obj2 = message2.getDataAsJson();
+
+    return areObjectsEqual(obj1, obj2);
+  };
+
+  public async shouldAutoRespondToProposal(
+    agentContext: AgentContext,
+    {
+      offerAttachment,
+      proposalAttachment,
+    }: CredentialFormatAutoRespondProposalOptions,
+  ) {
+    return this.areCredentialsEqual(proposalAttachment, offerAttachment);
+  }
+
+  public async shouldAutoRespondToOffer(
+    agentContext: AgentContext,
+    {
+      offerAttachment,
+      proposalAttachment,
+    }: CredentialFormatAutoRespondOfferOptions,
+  ) {
+    return this.areCredentialsEqual(proposalAttachment, offerAttachment);
+  }
+
+  public async shouldAutoRespondToRequest(
+    agentContext: AgentContext,
+    {
+      offerAttachment,
+      requestAttachment,
+    }: CredentialFormatAutoRespondRequestOptions,
+  ) {
+    return this.areCredentialsEqual(offerAttachment, requestAttachment);
+  }
+
+  public async shouldAutoRespondToCredential(
+    agentContext: AgentContext,
+    {
+      requestAttachment,
+      credentialAttachment,
+    }: CredentialFormatAutoRespondCredentialOptions,
+  ) {
+    const credentialJson =
+      credentialAttachment.getDataAsJson<JsonLdFormatDataVerifiableCredential>();
+    const w3cCredential = JsonTransformer.fromJSON(
+      credentialJson,
+      W3cJsonLdVerifiableCredential,
+    );
+    const request =
+      requestAttachment.getDataAsJson<JsonLdFormatDataCredentialDetail>();
+
+    try {
+      // This check is also done in the processCredential method, but we do it here as well
+      // to be certain we don't skip the check
+      this.verifyReceivedCredentialMatchesRequest(w3cCredential, request);
+
+      return true;
+    } catch (error) {
+      return false;
+    }
+  }
+
+  /**
+   * Returns an object of type {@link Attachment} for use in credential exchange messages.
+   * It looks up the correct format identifier and encodes the data as a base64 attachment.
+   *
+   * @param data The data to include in the attach object
+   * @param id the attach id from the formats component of the message
+   */
+  private getFormatData(data: unknown, id: string): Attachment {
+    const attachment = new Attachment({
+      id,
+      mimeType: "application/json",
+      data: new AttachmentData({
+        base64: JsonEncoder.toBase64(data),
+      }),
+    });
+
+    return attachment;
+  }
+}
diff --git a/libs/dtos/src/dtos/credo/w3c/credential/w3c.credential-schema.dto.ts b/libs/dtos/src/dtos/credo/w3c/credential/w3c.credential-schema.dto.ts
new file mode 100644
index 0000000000000000000000000000000000000000..8401d644094f7ff9bb3f2fe0c851530c3086ade4
--- /dev/null
+++ b/libs/dtos/src/dtos/credo/w3c/credential/w3c.credential-schema.dto.ts
@@ -0,0 +1,10 @@
+import { IsString } from "class-validator";
+import { IsUri } from "@aries-framework/core/build/utils";
+
+export class W3cCredentialSchemaDto {
+  @IsUri()
+  public id!: string;
+
+  @IsString()
+  public type!: string;
+}
diff --git a/libs/dtos/src/dtos/credo/w3c/credential/w3c.credential-status.dto.ts b/libs/dtos/src/dtos/credo/w3c/credential/w3c.credential-status.dto.ts
new file mode 100644
index 0000000000000000000000000000000000000000..fa5026dee7d21ef2b334b1c215d7ae605153613f
--- /dev/null
+++ b/libs/dtos/src/dtos/credo/w3c/credential/w3c.credential-status.dto.ts
@@ -0,0 +1,10 @@
+import { IsString } from "class-validator";
+import { IsUri } from "@aries-framework/core/build/utils";
+
+export class W3cCredentialStatusDto {
+  @IsUri()
+  public id!: string;
+
+  @IsString()
+  public type!: string;
+}
diff --git a/libs/dtos/src/dtos/credo/w3c/credential/w3c.credential-subject.dto.ts b/libs/dtos/src/dtos/credo/w3c/credential/w3c.credential-subject.dto.ts
new file mode 100644
index 0000000000000000000000000000000000000000..72b17610b028dc5416e2c842f419fe72783bc7ee
--- /dev/null
+++ b/libs/dtos/src/dtos/credo/w3c/credential/w3c.credential-subject.dto.ts
@@ -0,0 +1,8 @@
+import { IsOptional } from "class-validator";
+import { IsUri } from "@aries-framework/core/build/utils";
+
+export class W3cCredentialSubjectDto {
+  @IsUri()
+  @IsOptional()
+  public id?: string;
+}
diff --git a/libs/dtos/src/dtos/credo/w3c/credential/w3c.credential.dto.ts b/libs/dtos/src/dtos/credo/w3c/credential/w3c.credential.dto.ts
new file mode 100644
index 0000000000000000000000000000000000000000..61b43a26731de751d93452dd377eea94f5a467d3
--- /dev/null
+++ b/libs/dtos/src/dtos/credo/w3c/credential/w3c.credential.dto.ts
@@ -0,0 +1,68 @@
+import { Expose, Type } from "class-transformer";
+import {
+  IsInstance,
+  IsOptional,
+  IsRFC3339,
+  ValidateNested,
+} from "class-validator";
+
+import { W3cCredentialSchemaDto } from "./w3c.credential-schema.dto";
+import { W3cCredentialStatusDto } from "./w3c.credential-status.dto";
+import { W3cCredentialSubjectDto } from "./w3c.credential-subject.dto";
+import { W3cIssuerDto } from "./w3c.issuer.dto";
+import { IsCredentialJsonLdContext } from "@aries-framework/core/build/modules/vc/validators";
+import {
+  IsCredentialType,
+  IsW3cIssuer,
+  JsonObject,
+  W3cIssuerTransformer,
+} from "@aries-framework/core";
+import {
+  IsInstanceOrArrayOfInstances,
+  IsUri,
+  SingleOrArray,
+} from "@aries-framework/core/build/utils";
+
+export class W3cCredentialDto {
+  @Expose({ name: "@context" })
+  @IsCredentialJsonLdContext()
+  public context!: Array<string | JsonObject>;
+
+  @IsOptional()
+  @IsUri()
+  public id?: string;
+
+  @IsCredentialType()
+  public type!: Array<string>;
+
+  @W3cIssuerTransformer()
+  @IsW3cIssuer()
+  public issuer!: string | W3cIssuerDto;
+
+  @IsRFC3339()
+  public issuanceDate!: string;
+
+  @IsRFC3339()
+  @IsOptional()
+  public expirationDate?: string;
+
+  @Type(() => W3cCredentialSubjectDto)
+  @ValidateNested({ each: true })
+  @IsInstanceOrArrayOfInstances({ classType: W3cCredentialSubjectDto })
+  public credentialSubject!: SingleOrArray<W3cCredentialSubjectDto>;
+
+  @IsOptional()
+  @Type(() => W3cCredentialSchemaDto)
+  @ValidateNested({ each: true })
+  @IsInstanceOrArrayOfInstances({
+    classType: W3cCredentialSchemaDto,
+    allowEmptyArray: true,
+  })
+  public credentialSchema?: SingleOrArray<W3cCredentialSchemaDto>;
+
+  @IsOptional()
+  @Type(() => W3cCredentialStatusDto)
+  @ValidateNested({ each: true })
+  @IsInstance(W3cCredentialStatusDto)
+  public credentialStatus?: W3cCredentialStatusDto;
+}
diff --git a/libs/dtos/src/dtos/credo/w3c/credential/w3c.issuer.dto.ts b/libs/dtos/src/dtos/credo/w3c/credential/w3c.issuer.dto.ts
new file mode 100644
index 0000000000000000000000000000000000000000..23b19412df54eceb9eaa60181a095996746083b5
--- /dev/null
+++ b/libs/dtos/src/dtos/credo/w3c/credential/w3c.issuer.dto.ts
@@ -0,0 +1,6 @@
+import { IsUri } from "@aries-framework/core/build/utils";
+
+export class W3cIssuerDto {
+  @IsUri()
+  public id!: string;
+}
diff --git a/libs/dtos/src/dtos/credo/w3c/data-integrity/linked-data-proof.dto.ts b/libs/dtos/src/dtos/credo/w3c/data-integrity/linked-data-proof.dto.ts
new file mode 100644
index 0000000000000000000000000000000000000000..645c9a588597ebe7f4a6f5e6ab1e927618ad8fd3
--- /dev/null
+++ b/libs/dtos/src/dtos/credo/w3c/data-integrity/linked-data-proof.dto.ts
@@ -0,0 +1,36 @@
+import { IsOptional, IsString } from "class-validator";
+import { IsUri } from "@aries-framework/core/build/utils";
+
+export class LinkedDataProofDto {
+  @IsString()
+  public type!: string;
+
+  @IsString()
+  public proofPurpose!: string;
+
+  @IsString()
+  public verificationMethod!: string;
+
+  @IsString()
+  public created!: string;
+
+  @IsUri()
+  @IsOptional()
+  public domain?: string;
+
+  @IsString()
+  @IsOptional()
+  public challenge?: string;
+
+  @IsString()
+  @IsOptional()
+  public jws?: string;
+
+  @IsString()
+  @IsOptional()
+  public proofValue?: string;
+
+  @IsString()
+  @IsOptional()
+  public nonce?: string;
+}
diff --git a/libs/dtos/src/dtos/credo/w3c/data-integrity/w3c.json-ld.verifiable-credential.dto.ts b/libs/dtos/src/dtos/credo/w3c/data-integrity/w3c.json-ld.verifiable-credential.dto.ts
new file mode 100644
index 0000000000000000000000000000000000000000..627f5b309d5d614f069a031a6ef7e8d2aefb0adb
--- /dev/null
+++ b/libs/dtos/src/dtos/credo/w3c/data-integrity/w3c.json-ld.verifiable-credential.dto.ts
@@ -0,0 +1,15 @@
+import { ValidateNested } from "class-validator";
+import {
+  IsInstanceOrArrayOfInstances,
+  SingleOrArray,
+} from "@aries-framework/core/build/utils";
+import { LinkedDataProofTransformer } from "@aries-framework/core/build/modules/vc/data-integrity/models/LinkedDataProof";
+import { LinkedDataProofDto } from "./linked-data-proof.dto";
+import { W3cCredentialDto } from "../credential/w3c.credential.dto";
+
+export class W3cJsonLdVerifiableCredentialDto extends W3cCredentialDto {
+  @LinkedDataProofTransformer()
+  @IsInstanceOrArrayOfInstances({ classType: LinkedDataProofDto })
+  @ValidateNested()
+  public proof!: SingleOrArray<LinkedDataProofDto>;
+}
diff --git a/libs/dtos/src/dtos/credo/w3c/data-integrity/w3c.json-ld.verifiable-presentation.dto.ts b/libs/dtos/src/dtos/credo/w3c/data-integrity/w3c.json-ld.verifiable-presentation.dto.ts
new file mode 100644
index 0000000000000000000000000000000000000000..b9526063f4b9ca1d269fffc72336985d57328205
--- /dev/null
+++ b/libs/dtos/src/dtos/credo/w3c/data-integrity/w3c.json-ld.verifiable-presentation.dto.ts
@@ -0,0 +1,13 @@
+import {
+  IsInstanceOrArrayOfInstances,
+  SingleOrArray,
+} from "@aries-framework/core/build/utils";
+import { LinkedDataProofTransformer } from "@aries-framework/core/build/modules/vc/data-integrity/models/LinkedDataProof";
+import { LinkedDataProofDto } from "./linked-data-proof.dto";
+import { W3cPresentationDto } from "../presentation/w3c.presentation.dto";
+
+export class W3cJsonLdVerifiablePresentationDto extends W3cPresentationDto {
+  @LinkedDataProofTransformer()
+  @IsInstanceOrArrayOfInstances({ classType: LinkedDataProofDto })
+  public proof!: SingleOrArray<LinkedDataProofDto>;
+}
diff --git a/libs/dtos/src/dtos/credo/w3c/presentation/w3c.holder.dto.ts b/libs/dtos/src/dtos/credo/w3c/presentation/w3c.holder.dto.ts
new file mode 100644
index 0000000000000000000000000000000000000000..d439bcbfc06a85e36aa617c405754bfbff5c91b1
--- /dev/null
+++ b/libs/dtos/src/dtos/credo/w3c/presentation/w3c.holder.dto.ts
@@ -0,0 +1,6 @@
+import { IsUri } from "@aries-framework/core/build/utils";
+
+export class W3cHolderDto {
+  @IsUri()
+  public id!: string;
+}
diff --git a/libs/dtos/src/dtos/credo/w3c/presentation/w3c.presentation.dto.ts b/libs/dtos/src/dtos/credo/w3c/presentation/w3c.presentation.dto.ts
new file mode 100644
index 0000000000000000000000000000000000000000..4f5969baae4a212b15b418b0c313201e3fa771cb
--- /dev/null
+++ b/libs/dtos/src/dtos/credo/w3c/presentation/w3c.presentation.dto.ts
@@ -0,0 +1,45 @@
+import { Expose } from "class-transformer";
+import { ValidateNested, IsOptional } from "class-validator";
+
+import { W3cHolderDto } from "./w3c.holder.dto";
+import {
+  IsVerifiablePresentationType,
+  JsonObject,
+  W3cVerifiableCredentialTransformer,
+} from "@aries-framework/core";
+import { IsCredentialJsonLdContext } from "@aries-framework/core/build/modules/vc/validators";
+import {
+  IsInstanceOrArrayOfInstances,
+  IsUri,
+  SingleOrArray,
+} from "@aries-framework/core/build/utils";
+import {
+  IsW3cHolder,
+  W3cHolderTransformer,
+} from "@aries-framework/core/build/modules/vc/models/presentation/W3cHolder";
+import { W3cJsonLdVerifiableCredentialDto } from "../data-integrity/w3c.json-ld.verifiable-credential.dto";
+
+export class W3cPresentationDto {
+  @Expose({ name: "@context" })
+  @IsCredentialJsonLdContext()
+  public context!: Array<string | JsonObject>;
+
+  @IsOptional()
+  @IsUri()
+  public id?: string;
+
+  @IsVerifiablePresentationType()
+  public type!: Array<string>;
+
+  @W3cHolderTransformer()
+  @IsW3cHolder()
+  @IsOptional()
+  public holder?: string | W3cHolderDto;
+
+  @W3cVerifiableCredentialTransformer()
+  @IsInstanceOrArrayOfInstances({
+    classType: [W3cJsonLdVerifiableCredentialDto],
+  })
+  @ValidateNested({ each: true })
+  public verifiableCredential!: SingleOrArray<W3cJsonLdVerifiableCredentialDto>;
+}
diff --git a/libs/dtos/src/dtos/generics/credential.formatData.dto.ts b/libs/dtos/src/dtos/generics/credential.formatData.dto.ts
index 2060a05ae50e907bbb9335e5a488421ec81db75c..28bbc1b56a10da93eb4b756fc994842cda541899 100644
--- a/libs/dtos/src/dtos/generics/credential.formatData.dto.ts
+++ b/libs/dtos/src/dtos/generics/credential.formatData.dto.ts
@@ -13,4 +13,6 @@ export class CredentialFormatDataDto {
   public anoncredsOffer?: AnonCredsCredentialOffer;
   public anoncredsRequest?: AnonCredsCredentialRequest;
   public anoncredsCredential?: AnonCredsCredential;
+
+  public all?: unknown;
 }
diff --git a/libs/dtos/src/dtos/requests/offer.credential.request.dto.ts b/libs/dtos/src/dtos/requests/offer.credential.request.dto.ts
index 2dc3595ab3fbb8ba6d9704d4f2a7909276adb46e..9cea64c90950d36aadd29ab0bf2765d7576d9e2a 100644
--- a/libs/dtos/src/dtos/requests/offer.credential.request.dto.ts
+++ b/libs/dtos/src/dtos/requests/offer.credential.request.dto.ts
@@ -7,6 +7,7 @@ import {
   ValidateNested,
 } from "class-validator";
 import { Type } from "class-transformer";
+import { W3cCredentialDto } from "../credo/w3c/credential/w3c.credential.dto";
 
 export class OfferCredentialAttributes {
   @IsString()
@@ -34,3 +35,16 @@ export class OfferCredentialRequestDto {
   @Type(() => OfferCredentialAttributes)
   attributes: Array<OfferCredentialAttributes>;
 }
+
+export class OfferJsonCredentialRequests {
+  @IsString()
+  @IsNotEmpty()
+  @IsOptional()
+  connectionId?: string;
+
+  doc: W3cCredentialDto;
+}
+
+export class SignJsonCredentialRequests {
+  doc: W3cCredentialDto;
+}
diff --git a/libs/dtos/src/index.ts b/libs/dtos/src/index.ts
index b9c5a35e1e3438b9057f02cfd751ba970342e02b..03062d4d6de377a29760704674c7c7b2d3bebd33 100644
--- a/libs/dtos/src/index.ts
+++ b/libs/dtos/src/index.ts
@@ -27,6 +27,17 @@ export * from "./dtos/requests/request.proof.dto";
 export * from "./dtos/requests/make.basic.message.request.dto";
 export * from "./dtos/requests/create.invitation.request.dto";
 
+export * from "./dtos/credo/w3c/credential/w3c.credential.dto";
+export * from "./dtos/credo/w3c/credential/w3c.credential-schema.dto";
+export * from "./dtos/credo/w3c/credential/w3c.credential-status.dto";
+export * from "./dtos/credo/w3c/credential/w3c.credential-subject.dto";
+export * from "./dtos/credo/w3c/credential/w3c.issuer.dto";
+export * from "./dtos/credo/w3c/presentation/w3c.holder.dto";
+export * from "./dtos/credo/w3c/presentation/w3c.presentation.dto";
+export * from "./dtos/credo/w3c/data-integrity/linked-data-proof.dto";
+export * from "./dtos/credo/w3c/data-integrity/w3c.json-ld.verifiable-credential.dto";
+export * from "./dtos/credo/w3c/data-integrity/w3c.json-ld.verifiable-presentation.dto";
+
 export * from "./dtos/responses/request.proof.response.dto";
 export * from "./dtos/responses/credential.offer.response.dto";
 export * from "./dtos/responses/create.invitation.response.dto";