Skip to Content
API and DashboardPresentation Templates

Presentation Templates

To use Paradym to verify information from a holder you’ll first need to create a presentation template. A presentation template defines what attributes and/or information the holder should present as proof. Once created, a template can be used to request as many presentations as you want.

Overview

When creating your presentation template you are basically making the blueprint for a presentation request that can be re-used. The main things you need to know before creating a template are:

  • The credential format and type of the credential(s) you want to request
  • The trusted issuer(s)
  • The specific attributes you want to request
  • [Optional] Any requirements the specific attributes need to match
  • [Optional] The request authentication method when using sd-jwt-vc or mdoc credentials

Note that it is currently not possible to combine all credential formats in a single presentation template. You have to decide which credential format to request, and this will also influence the exchange protocol to use for the request. Based on the format that is going to be used for issuance of the credential, you need to use the same format for verification of the credential:

We recommend to always configure the trusted issuers on a presentation template, as everyone can issue a credential based on a certain credential type. It is the issuer of the credential that determines whether you trust or accept it. If you don’t configure the issuers on a presentation template, you must manually verify the issuer of a submitted credential afterwards and ensure you trust the issuer of that credential. Read more on creating and configuring trusted entities.

If you’re verifying a credential issued by one or more issuer(s) that is not yourself, you need to get hold of the following information to be able to verify credentials issued by them:

  • The credential format. Paradym supports sd-jwt-vc, mdoc or anoncreds for verification.
  • The trusted issuers. Paradym supports X.509 certificates and DIDs.
  • The attributes of the credential.

Presentation Template Contents

Each presentation template contains some general information like a name and an optional description.

If the protocol supports it, the description shows the recipient why the information is requested. It is optional: when you leave it out, it is excluded from the generated request (DIDComm or DIF Presentation Exchange Definition). Note that the description is not sent when using the v1 OpenID4VC version, as DCQL does not allow to define the purpose of the request.

Credentials

In addition to the general information, each presentation template needs to define one or multiple (up to 20) credentials that will be requested.

This is where you add a credential type as well as the specific fields you want to request. The type (SD-JWT VC and mDoc) or schema (Anoncreds) of the credential is a unique and re-usable identifier that can be used to request a presentation involving this specific credential type. For example a verifier might specify that they want to verify attributes as defined in a mobile drivers license (mDL) and use the org.iso.18013.5.1.mDL doctype (as specified in ISO 18013-5). The credential type can be selected from previously created paradym credential types, or it can be added manually for other types. A template can request each credential type once per format.

For each credential you want to include in the presentation request a name and description can optionally be provided. Currently the individual credential names and descriptions are not shown to the recipient, but are used in the dashboard to provide additional context.

Each credential has an id, unique within the template. You can set it yourself, for example payment-account. Otherwise Paradym assigns a random id. When you update a template without the id of a credential, the credential keeps its id as long as its format and type (or schema) stay the same. Transactions refer to credentials by their id, and a verification returns the id of the template credential each presented credential was requested for.

  • The format of the credential is where you define what kind of verifiable credential you will request from the wallet. Each format has its own benefits and features. Currently Paradym supports SD JWT VCs (sd-jwt-vc), mDoc (mdoc) and Anoncreds (anoncreds) for presentation templates. Read more about the different standards and protocols.

The attributes are where it gets specific.

  • With the attribute key, information from the attribute can be requested in a proof request programmatically (e.g. request the value of job-title). If only the key is defined then the proof request (if accepted) will return the value of this key from this credential type.
  • Additionally you can optionally define the attribute type, with which the request can be further specified (e.g. request the value of job-title only if it is a string type). The available types are string, number, boolean, date, and object.
  • As a third level, you can define the specific value (e.g. request the value of job-title only if it is a string type AND only if it matches developer)
  • For number values you can also define a range (minimum, maximum, or both). Anoncreds credentials support range proofs, and only whether the value lies within the range will be shared (true or false), not the actual value. This allows you to verify someones date of birth is before 20001012 (12 october 2000), without actually getting to know their date of birth.

Not all credential formats support all types. SD-JWT VC supports all types, and Anoncreds supports only date and number.

mDoc supports all types as values in an issued credential, but does not allow specifying the type or value of an attribute in a presentation template. This limitation is defined in ISO 18013-7 and enforced by Paradym to maximize interoperability.

Transactions

Experimental: this may still change before it is stable.
Transactions are available from the Pro tier upwards.

A presentation template can optionally define one or more transactions the holder must authorize when presenting, such as a payment or a document signature. This uses OpenID4VP transaction_data: the wallet shows the transaction to the holder and, on approval, signs a hash of it into the key binding of the presented credential. The verified presentation is then cryptographically bound to that exact transaction.

A transaction defines:

  • The type, which identifies the transaction to the wallet and must be unique within the template.
  • The credentialIds: the id of one or more sd-jwt-vc credentials in the same template. The wallet signs the transaction with one of the presented credentials. An id you set must be unique within the template and must not end in -cert or -did.
  • The attributes every verification request must supply for this transaction, with an optional type (string, number, boolean, date or datetime), name and description. An attribute cannot be named type, credential_ids or transaction_data_hashes_alg.

The wallet signs a sha-256 hash of each transaction into the key binding of the presented credential, as defined for SD-JWT VC in OpenID4VP.

The template only defines the shape of a transaction. The actual values, such as the amount of a payment, are provided when creating a verification request.

Transactions are only supported with OpenID4VC version v1, and only sd-jwt-vc credentials can sign a transaction. A template with transactions can still request mdoc credentials alongside the signing credential.

Allowed OpenID4VP flows

Experimental: this may still change before it is stable.

Each template carries an openId4Vc.allowedFlows list that restricts which OpenID4VP flows may be used with it. Both flows are invoked over a URI (a deeplink or a QR code):

  • sameDevice is the redirect flow. A verification request uses it by providing both a challenge and a redirectUri, so the wallet returns the holder to the device that made the request. That is what binds the result to the device that presented, and what mitigates session fixation.
  • crossDevice is the flow without that binding: the wallet posts its response and returns nobody. A verification request uses it by providing neither.

A request using a flow that is not listed is rejected with a 400. Leaving allowedFlows out, which is the default, places no restriction:

{ "name": "My presentation template", "openId4Vc": { "allowedFlows": ["sameDevice"] } }

The names describe what the server can verify, whether the request asked for the holder to be sent back, rather than a device it has no way to inspect. A sameDevice request from a holder whose wallet is on another phone simply cannot be completed, which is the point. See Assurance level and security model for when this matters.

Leave allowedFlows out unless you need to restrict the template. Omitting it also keeps placing no restriction on flows Paradym supports later, such as the W3C Digital Credentials API , which is not invoked over a URI and so has no same-device or cross-device distinction. An empty list is not a way to say the same thing: it permits no flow at all, so it is rejected.

The list only applies to OpenID4VC. DIDComm verification requests using the same template are unaffected.

The list means the same for verification with OpenID Connect using this template: it lists the flows a request may be completed with. A list without crossDevice means the holder has to open their wallet on the device they started on, so scanning the code is refused rather than reported as lower assurance. A list without sameDevice completes every request as cross-device: the hosted page only hands out the link that does not return the holder, who comes back to the page themselves. A relying party can narrow the list further for one request with acr_values.

Creating a presentation template

Creating your first presentation template is easiest to do within the dashboard , especially if you want to create a presentation request using a credential template you’ve created. It guides you through configuring the elements of the presentation request.

If you’re going to use the API to create a presentation template, and you’ve created a presentation template before from within the dashboard you can retrieve it from the API (Retrieve Presentation Template ) and use that for creating a similar presentation template using the API.

The easiest way to get started with the API is using the interactive API Reference . If you would like to follow along using a custom API client, make sure follow the Quickstart guide. You can read more on interacting with the API.

To create a presentation template in the API we will make a POST request to https://api.paradym.id/v1/wallets/{walletId}/templates/presentations. For detailed information on the endpoint, refer to the create presentation template  page in the API reference.

When creating a presentation template through the API you can optionally also provide a list of trusted issuers and an authentication method. Read the docs on trusted entities to learn more about creating and linking a trusted entity to a presentation template.

SD JWT VC

For credentials with sd-jwt-vc format, we need to provide a type value. You can copy this from your credential template, or someone else can share this with you. Make sure to change the attributes based on your credential template.

POST/v1/wallets/{walletId}/templates/presentationsOpen in Reference
{
  "name": "Verify membership status",
  "description": "This information is requested to verify if you are still and active member",
  "verifier": {
    "signer": "certificate",
    "keyType": "P-256"
  },
  "credentials": [
    {
      "description": "These attributes are requested to verify your paradym membership",
      "name": "Request for Paradym MemberCard",
      "format": "sd-jwt-vc",
      "type": "https://metadata.paradym.id/types/28dc88-MemberCard",
      "trustedIssuers": [
        "cm85v8gnx003wuqnk31p2k80x"
      ],
      "attributes": {
        "first_name": {
          "type": "string",
          "value": "myValue"
        },
        "loyalty_points": {
          "type": "number"
        },
        "active": {
          "type": "boolean",
          "value": true
        }
      }
    }
  ]
}

mDoc

Requesting an mDoc credential in a presentation template is similar to an SD-JWT VC, and can even be combined in one request with SD-JWT VC credentials. Some differences:

  • mDoc credentials do not support specifying the types or values of attributes, neither is requesting nested attributes possible. Only the top-level attributes you want to request from which namespaces can be configured.
  • mDoc credentials are structured based on namespaces. An mDoc can contain multiple namespaces, and each namespace can contain attributes. An example is the org.iso.18013.5.1 namespace, which contains the given_name attribute.
  • mDoc credentials support an additional intentToRetain property, which is defined in ISO 18013-5 and defines whether the value will be retained (stored) after the verification is processed. The default value is false, but should be changed if you will store the value. Changing this value does not affect processing in Paradym, and merely acts as a hint to the wallet.
POST/v1/wallets/{walletId}/templates/presentationsOpen in Reference
{
  "name": "Rent a car",
  "description": "To rent a car we need to verify your drivers license",
  "verifier": {
    "signer": "did:web"
  },
  "credentials": [
    {
      "format": "mdoc",
      "type": "org.iso.18013.5.1.mDL",
      "trustedIssuers": [
        "cm85v8gnx003wuqnk31p2k80x"
      ],
      "attributes": {
        "org.iso.18013.5.1": {
          "properties": {
            "family_name": {},
            "given_name": {
              "intentToRetain": true
            },
            "driving_privileges": {
              "intentToRetain": false
            }
          }
        }
      }
    }
  ]
}

Transactions

To have the holder authorize a transaction as part of the presentation, give the signing credential an id and add a transactions array. Each transaction references the credential(s) that may sign it by credentialIds, and declares the attributes a verification request must supply.

POST/v1/wallets/{walletId}/templates/presentationsOpen in Reference
{
  "name": "Payment authorization",
  "description": "Authorize a payment with your payment account",
  "verifier": {
    "signer": "certificate",
    "keyType": "P-256"
  },
  "credentials": [
    {
      "id": "payment-account",
      "name": "Payment account",
      "format": "sd-jwt-vc",
      "type": "https://metadata.paradym.id/types/28dc88-PaymentAccount",
      "trustedIssuers": [
        "cm85v8gnx003wuqnk31p2k80x"
      ],
      "attributes": {
        "account_id": {
          "type": "string"
        }
      }
    }
  ],
  "transactions": [
    {
      "type": "example.payment",
      "credentialIds": [
        "payment-account"
      ],
      "attributes": {
        "amount": {
          "type": "string",
          "name": "Amount"
        },
        "currency": {
          "type": "string",
          "name": "Currency"
        },
        "payee": {
          "type": "string",
          "name": "Payee"
        }
      }
    }
  ]
}

Anoncreds

Requesting an Anoncreds credential in a presentation template is very similar to an SD-JWT VC, however there are some differences:

  • Anoncreds credentials only support string and number types. For boolean types you can use number with values 1 and 0. For date types you can use number and encode the date as yyyymmdd. This allows you to do range predicate checks, e.g. requesting that date_of_birth is less than 20001012 (before 12 october 2000).
  • You need to provide a schema instead of a type to indicate which credential type should be requested.
POST/v1/wallets/{walletId}/templates/presentationsOpen in Reference
{
  "name": "Verify membership status",
  "description": "This information is requested to verify if you are still and active member",
  "credentials": [
    {
      "description": "These attributes are requested to verify your paradym membership",
      "name": "Request for Paradym MemberCard",
      "format": "anoncreds",
      "schema": "did:cheqd:testnet:fb8a3467-a72d-41d7-bde0-50c85febbef4/resources/efd5749c-fff5-4dfc-9e30-d75ec92f15da",
      "trustedIssuers": [
        "cm85v8gnx003wuqnk31p2k80x"
      ],
      "attributes": {
        "first_name": {
          "type": "string"
        },
        "loyalty_points": {
          "type": "number",
          "minimum": 500
        },
        "active": {
          "type": "number",
          "value": 1
        }
      }
    }
  ]
}

The return value will be approximately the same as the payload you provided, with a few extra fields (such as id, createdAt, and updatedAt) added.

Even though the examples above are all separate per format, it is possible to mix sd-jwt-vc and mdoc credentials in one presentation template.

EU Registration Certificate

Experimental: this may still change before it is stable.

In an EUDI Wallet ecosystem, a registrar issues relying parties two certificates. The access certificate says who you are, and authenticates your requests. The EU Registration Certificate (Wallet-Relying Party Registration Certificate, ETSI TS 119 475) says what you are registered to request, so the wallet can show this to the holder and refuse a request that asks for more. Paradym implements ETSI TS 119 475 v1.2.1.

EU Registration Certificates are available from the Builder tier upwards.

Add one to a presentation template and Paradym sends it with every request created from that template. For OpenID4VP that is the verifier_info parameter:

"verifier_info": [{ "format": "registration_cert", "data": "ZXlKMGVYQWlPaUp5WXkxM2NuQXJhbmQwSWku..." }]

In the dashboard, paste the registration certificate (a JWT with typ rc-wrp+jwt) into the EU Registration section of the template. The dashboard checks it as you paste it and shows who it was issued to. Over the API, set eudi.registrationCertificate:

{ "name": "Verify your identity", "verifier": { "signer": "certificate", "keyType": "P-256" }, "eudi": { "registrationCertificate": "eyJ0eXAiOiJyYy13cnArand0Ii..." } }

A registration certificate can only be added when:

  • The template requests sd-jwt-vc or mdoc credentials. AnonCreds templates can’t have one.
  • The template authenticates with an X.509 certificate, and that certificate is the access certificate your registrar issued, imported through a certificate signing request.
  • The sub of the registration certificate (or intermediary.sub, when an intermediary acts on your behalf) matches the identifier in the subject of the access certificate. That is the organizationIdentifier for a legal person, and the serialNumber for a natural person.
  • The wallet uses OpenID4VC version v1.

Request only the credentials and claims the registration certificate lists. A wallet may refuse a request that asks for more.

Paradym validates the registration certificate against ETSI TS 119 475 when you save the template. It rejects a registration certificate that is malformed, has expired, does not match the access certificate, or whose signature does not verify against the certificate in its x5c header. Whether the registrar is trusted and whether the registration certificate is revoked is left to the wallet.

A registration certificate belongs to one access certificate. When you replace the access certificate, or the registration certificate expires, request a new registration certificate and update the template. Until then, wallets may reject the requests created from it.

Registrar Dataset

ETSI TS 119 472-2 also has the request carry the data your registrar provided about you and the intended use, even when you have no registration certificate. The wallet uses it to look up your registration at the registrar. Some ecosystems, such as WE BUILD, require it. Set it with eudi.registrarDataset, or paste it as JSON into the EU Registration section of the template:

{ "eudi": { "registrarDataset": { "identifier": "VATPL-66312312312", "srvDescription": [{ "lang": "en", "value": "Example Verifier Service" }], "registryURI": "https://registrar.example.org/api", "intendedUseIdentifier": "urn:webuild:intended-use:001", "purpose": [{ "lang": "en", "value": "Age verification" }], "policyURI": "https://verifier.example.org/privacy" } } }

Paradym requires the six members above. ETSI TS 119 475 names the localized text content and WE BUILD names it value, so either is accepted. Other members, such as credential, are sent as given. The identifier must be the relying party: the sub of the registration certificate, or without one, the organizationIdentifier (or serialNumber) of the access certificate. Copy the other values from your registrar. Paradym does not check them against the registration certificate, but wallets may.

The same conditions apply as for a registration certificate: the template authenticates with the access certificate your registrar issued, requests sd-jwt-vc or mdoc credentials, and the wallet uses OpenID4VC version v1.

Last updated on