---
id: openID4vc-send-verify-credentials
title: "Verify Credentials with OpenID4VP"
hide_title: true
sidebar_label: Send and Verify Credential
slug: /openID4vc-send-verify-credentials/
description: "Step-by-step OpenID4VP verification: get an API key, build a presentation definition, generate the QR request, and validate the returned presentation, with code."
keywords: [OpenID4VP, credential verification, OID4VP, verifiable credentials, presentation definition, DCQL, relying party, verifier, Organisation Wallet, European Business Wallet, EUDI Wallet, API, send credentials]
---

> **Build this with an AI coding agent.** Install the iGrant.io Agent Skills, then ask your agent to build the integration:
>
> ```bash
> npx skills add L3-iGrant/skills
> ```


import Link from "@docusaurus/Link";
import VideoPlayer from "@site/src/components/VideoPlayer";
import NoteBox from "@site/src/components/NoteBox";

<head>
  <title>Verify Credentials with OpenID4VP: API Guide &amp; Code Examples</title>
  <meta name="description" content="Step-by-step OpenID4VP verification: get an API key, build a presentation definition, generate the QR request, and validate the returned presentation, with code." />
  <meta property="og:image" content="https://docs.igrant.io/img/cDocs/eudi-wallet-with-openid4vc.webp" />
  <meta name="twitter:image" content="https://docs.igrant.io/img/cDocs/eudi-wallet-with-openid4vc.webp" />
  <script type="application/ld+json">
    {JSON.stringify({
      "@context": "https://schema.org",
      "@graph": [
        {
          "@type": "Article",
          "headline": "Verify Credentials with OpenID4VP",
          "image": "https://docs.igrant.io/img/cDocs/eudi-wallet-with-openid4vc.webp",
          "author": { "@type": "Organization", "name": "iGrant.io", "url": "https://igrant.io" },
          "publisher": {
            "@type": "Organization",
            "name": "iGrant.io",
            "url": "https://igrant.io",
            "logo": { "@type": "ImageObject", "url": "https://igrant.io/assets/images/favicons/preview.png" }
          },
          "dateModified": "2026-07-18",
          "mainEntityOfPage": "https://docs.igrant.io/docs/openID4vc-send-verify-credentials/"
        },
        {
          "@type": "FAQPage",
          "mainEntity": [
            {
              "@type": "Question",
              "name": "What is OpenID4VP?",
              "acceptedAnswer": { "@type": "Answer", "text": "OpenID for Verifiable Presentations (OpenID4VP) is an OpenID Foundation specification that defines how a verifier (relying party) requests verifiable credentials from a holder's wallet and how the wallet returns them for cryptographic verification, typically via a QR code, deeplink or NFC tag." }
            },
            {
              "@type": "Question",
              "name": "How does a verifier verify a credential with OpenID4VP?",
              "acceptedAnswer": { "@type": "Answer", "text": "The verifier creates a presentation definition describing the required credentials or claims, sends a verification request (often as a QR code), and receives a vp_token from the holder. The verifier then cryptographically verifies the presentation and can check the issuer against a recognised trust list." }
            },
            {
              "@type": "Question",
              "name": "What is a presentation definition?",
              "acceptedAnswer": { "@type": "Answer", "text": "A presentation definition is a JSON object that specifies which credentials and claims a verifier requires. It can follow the DIF Presentation Exchange standard, or you can use the newer Digital Credential Query Language (DCQL) introduced in OpenID4VP 1.0." }
            },
            {
              "@type": "Question",
              "name": "Can a verifier request only specific claims from a credential?",
              "acceptedAnswer": { "@type": "Answer", "text": "Yes. Using selective disclosure, a verifier can request only the specific claims it needs, such as an age-over-18 boolean instead of a full date of birth, so the holder shares the minimum data required for the transaction." }
            }
          ]
        }
      ]
    })}
  </script>
</head>

# Verify Credentials with OpenID4VP

In the realm of digital identity, verifiers, also known as Relying Parties (RP), play a crucial role in validating the authenticity of presented credentials. Utilising the OpenID for Verifiable Presentations (OpenID4VP) protocol, verifiers can request, receive, and assess verifiable credentials in a secure and standardised manner.​
This guide outlines the process for verifiers to follow:

- Define the specific credentials or claims they require through a presentation definition.
- Initiate a verification request to holders, often facilitated via QR codes or direct links.
- Receive and validate the verifiable presentation returned by the holder's wallet, ensuring the data's integrity and authenticity.​

By following the steps below, verifiers can request digital credentials and verify them, fostering trust in digital interactions.

### Step 1: Get the API Key

To obtain your API key, please contact [support@igrant.io](mailto:support@igrant.io?subject=Request%20API%20Key). Once you have received your API key, enter it in the field below and click the **Set API Key** button to save it for future use.

import { ApiKeyManager } from "@site/src/components/ApiKeyManager";

<ApiKeyManager />

### Step 2: Create Presentation Definition (Verifier Admin)

To create a presentation definition for requesting proof, you can run the code block below using the **Run** button. Alternatively, you can manually copy the code block and use it in the body of the API request provided [here](/docs/openid4vc-api/config-digital-wallet-open-id-presentation-definition).

import Step2 from "@site/src/components/Verification/Step2";

<Step2
  requestBodyOptions={[
    {
      label: "W3C VC (JWT)",
      requestBodyJson: {
        label: "Legal PID (W3C VC)",
        presentationDefinition: {
          id: "66e3e5b5-df50-4eab-a8ef-8945c3b68d2c",
          input_descriptors: [
            {
              id: "71cec094-d5df-4df0-b2a3-1f7ce938373e",
              name: "",
              purpose: "",
              format: {
                jwt_vc_json: {
                  alg: ["ES256"],
                },
              },
              constraints: {
                fields: [
                  {
                    path: ["$.type"],
                    filter: {
                      type: "array",
                      contains: {
                        const: "LegalPersonIdentificationData",
                      },
                    },
                  },
                  {
                    path: ["$.credentialSubject.identifier"],
                  },
                  {
                    path: ["$.credentialSubject.legalName"],
                  },
                ],
              },
            },
          ],
        },
      },
    },
    {
      label: "IETF SD-JWT",
      requestBodyJson: {
        label: "Legal PID (SD-JWT)",
        presentationDefinition: {
          id: "d70b761e-4f4d-4261-9c2a-b0ca05cc15dd",
          input_descriptors: [
            {
              id: "94e44bf9-fefb-4dad-8908-42950d268143",
              name: "",
              purpose: "",
              format: {
                "dc+sd-jwt": {
                  alg: ["ES256"],
                },
                "vp+sd-jwt": {
                  alg: ["ES256"],
                },
              },
              constraints: {
                fields: [
                  {
                    path: ["$.vct"],
                    filter: {
                      type: "string",
                      const: "LegalPersonIdentificationData",
                    },
                  },
                  {
                    path: ["$.identifier"],
                  },
                  {
                    path: ["$.legalName"],
                  },
                ],
                limit_disclosure: "required",
              },
            },
          ],
        },
      },
    },
  ]}
/>

<NoteBox title="Tip:" variant="tip">
Once a presentation definition is created, the <code>presentationDefinitionId</code> can be reused to verify multiple credentials (Step 3).
</NoteBox>

### Step 3: Create Verification Request (Verfier/Relying Party)

To create the verification request, execute the code block below using the **Run** button. Alternatively, you can manually copy the code block and use it in the body of the API request available [here](/docs/openid4vc-api/config-create-digital-wallet-open-id-verification-request-v-3).

After receiving the response, toggle the button provided to dynamically generate a QR code. The EUDI Wallet/Holder can then accept the credential offer using the Data Wallet (or any other EU Digital Identity Wallet) by either scanning the QR code or directly accessing the verification request on their mobile device, such as via a browser.

import Step3 from "@site/src/components/Verification/Step3";

<Step3
  initialJsonData={{
    presentationDefinitionId: "<presentationDefinitionId>",
    requestByReference: true,
  }}
/>

The presentation definition provided adheres to the specifications outlined in the DIF Presentation Exchange standard, as detailed [here](https://identity.foundation/presentation-exchange/).

:::tip Building queries with DCQL instead?
OpenID4VP 1.0 introduces the **Digital Credential Query Language (DCQL)** as the modern successor to DIF Presentation Exchange. Start with the [DCQL overview](/docs/dcql-overview/), then work through a runnable, step-by-step tutorial for your scenario:

- [Trusted Authorities](/docs/dcql-basic-credential-query-with-trusted-authority/) - restrict a credential to trusted issuers
- [Claim Sets (Selective Disclosure)](/docs/dcql-2-4-2-claim-set-age-verification/) - age verification with minimal disclosure
- [Credential Sets (Alternatives)](/docs/dcql-2-4-3-credential-set-proof-of-identity-alternatives/) - accept any one of several identity credentials
- [Combined Credential Sets](/docs/dcql-2-4-4-kyc-request-photo-id-address-proof/) - KYC with Photo ID plus address proof
- [Mandatory and Optional Sets](/docs/dcql-2-4-5-student-transport-pass/) - student transport pass with optional extras
- [Multiple Credential Instances](/docs/dcql-2-4-6-loan-application-multiple-bank-statements/) - request several recent bank statements
- [Values Constraint](/docs/dcql-2-4-7-delivery-service-restricted-postal-codes/) - accept a credential only for allowed postal codes
:::

### Step 4: Send and Receive Verifiable Presentation (Holder)

The holder wallet accepts (consents) to send the requested credentials.

### Step 5: Send and Receive Verifiable Presentation (Verifier/Relying Party)

* The Verfier (Relying Party) receives the requested credentials and can verify it. They may read the received credential by executing the [Read Verification History API](/docs/openid4vc-api/config-read-digital-wallet-open-id-verification-history-v-3).
* From the response received, the `vpTokenResponse` can be decoded using [JWT Decoder](/docs/devtools-jwt-decoder/).
* From decoded response, the `verifiableCredential` inside the 'vp' can be further decoded to view the received credentials.

:::info Trust status of the verifier
The wallet checks whether the verifier can be matched against a recognised trust list. The verification response exposes this through the `isVerifiedWithTrustList` and `trustServiceProvider` fields. If the verifier cannot be matched, the Data Wallet shows a **"Service provider not verified"** warning. See [The "Service provider not verified" notice](/docs/trust-untrusted-service-provider/) and [Trust in the Wallet Ecosystem](/docs/trust-overview/).
:::

## Try It Yourself (With Demo Video)

Watch the below demo to learn verify credential API and try it out yourselves:

<VideoPlayer
  videoId="xD4TLfdnSG0"
  title="OpenID4VP Verification Demo"
  description="Learn how to send and verify credentials using OpenID4VP protocol with iGrant.io Digital Wallets."
  uploadDate="2024-01-01"
  duration="PT10M"
/>
