# Truvity Docs > Developer documentation for the Truvity platform — SSI, EUDI Wallet Connector, Verifiable Credentials, and more. ## Changelog ### Changelog #### July 14, 2026[​](#july-14-2026 "Direct link to July 14, 2026") EUDIW ConnectorAPI v1.3.0 ##### LoTL-driven trust anchor verification[​](#lotl-driven-trust-anchor-verification "Direct link to LoTL-driven trust anchor verification") The connector now verifies credential issuers against the EU List of Trusted Lists (LoTL) hierarchy, determining whether each issuer is recognised by the EU trust framework and what category of credential it is authorised to produce. Trust outcomes are reported as enriched fields on `FULFILLED` callback payloads. **Key capabilities:** * **Credential category determination**—the connector classifies each credential as PID, QEAA, PuB-EAA, or non-qualified EAA based on the issuer's trust list entry. * **Trust resolution modes**—LoTL-enabled mode (production, dynamic resolution) and static-only mode (fallback, manual trust anchors). * **Trust verification policy**—configure per credential category: `enforce` (trust failure blocks the flow), `evaluate` (default—trust outcomes reported informationally), or `disabled` (trust fields omitted). * **`trusted_authorities` DCQL constraint**—narrow acceptance to issuers resolvable through the LoTL/LoTE hierarchy using the `etsi_tl` authority type. * **Trust failure reason reporting**—four coarse failure codes: `issuer_not_found`, `issuer_withdrawn`, `issuer_suspended`, `trust_list_unavailable`. ##### New callback fields[​](#new-callback-fields "Direct link to New callback fields") | Field | Type | Description | | ------------------------ | ------- | ------------------------------------------------------------ | | `credentialCategory` | string | PID, QEAA, PUB\_EAA, or NON\_QUALIFIED\_EAA | | `trustSource` | string | `lotl`, `static`, or `untrusted` | | `supervisoryMemberState` | string | ISO 3166-1 alpha-2 code | | `qualifiedStatus` | boolean | Qualified trust service entry | | `trustDataTimestamp` | string | ISO 8601 trust data snapshot timestamp | | `trustFailureReason` | string | Failure code when `isTrusted: false` | | `staleTrustData` | object | `{ cachedFallback, pastNextUpdate }`—stale trust data signal | ##### New configuration variables[​](#new-configuration-variables "Direct link to New configuration variables") | Variable | Default | Description | | ----------------------------------- | ---------- | ------------------------------------------ | | `X509_TRUST_RESOLUTION_MODE` | `static` | Trust resolution mode (`lotl` or `static`) | | `X509_TRUST_LIST_SOURCES` | (none) | Structured trust list source configuration | | `X509_TRUST_STORE_REFRESH_INTERVAL` | `6h` | Trust store refresh interval | | `X509_STALENESS_WINDOW` | `24h` | Maximum cached trust data age | | `X509_LOTL_FETCH_TIMEOUT` | `30s` | HTTP timeout for trust list fetches | | `X509_MAX_RESPONSE_BYTES` | `10485760` | Maximum trust list response body size | ##### Documentation[​](#documentation "Direct link to Documentation") * **New:** [LoTL trust verification](/eudiw-connector/explanations/trust-revocation/lotl-verification.md)—conceptual explanation * **Updated:** [Configure trust anchor verification](/eudiw-connector/how-to-guides/configure-trust-anchors.md)—restructured with LoTL mode first * **Updated:** [Callback events](/eudiw-connector/reference/callback-events.md)—enriched trust fields #### June 5, 2026[​](#june-5-2026 "Direct link to June 5, 2026") EUDIW ConnectorAPI v1.2.2 ##### X.509 certificate chain validation and CRL revocation checking[​](#x509-certificate-chain-validation-and-crl-revocation-checking "Direct link to X.509 certificate chain validation and CRL revocation checking") The connector now validates X.509 certificate chains in SD-JWT VC credentials (the `x5c` header, mandatory in HAIP-compliant ecosystems), and optionally checks certificate revocation status against Certificate Revocation Lists (CRLs). **Chain-internal validation** runs automatically whenever a credential includes an `x5c` certificate chain. The connector verifies intra-chain signatures, certificate validity periods, and Basic Constraints and Key Usage extensions. If validation fails, the credential fails verification. **Trust anchor resolution and CRL checking** is an optional feature, disabled by default. When enabled, the connector resolves the chain's last certificate against configured trust anchors and fetches CRLs to check whether any certificate in the chain has been revoked. ##### API[​](#api "Direct link to API") * **New:** `isCertificateRevoked` field on credential objects in `FULFILLED` callback events. Present when `supportTrustAnchor: true`. Indicates whether any certificate in the issuer's X.509 chain was found on a CRL. See [Callback events](/eudiw-connector/reference/callback-events.md). * **Changed:** `supportTrustAnchor: true` now gates two fields: `isTrusted` and `isCertificateRevoked`. ##### Configuration[​](#configuration "Direct link to Configuration") Three new environment variables control the feature: | Variable | Default | Description | | -------------------------- | ------- | ------------------------------------------------------------ | | `X509_VERIFY_TRUST_ANCHOR` | `false` | Enable trust anchor resolution and CRL checking | | `X509_TRUST_ANCHORS` | `""` | Comma-separated base64-encoded DER trust anchor certificates | | `X509_CRL_TIMEOUT_SECONDS` | `10` | HTTP timeout for CRL fetch requests | ##### Documentation[​](#documentation-1 "Direct link to Documentation") * **New guide:** [Configure X.509 trust anchor verification](/eudiw-connector/how-to-guides/configure-trust-anchors.md) — step-by-step setup for trust anchor configuration and CRL checking. * **Updated:** [Revocation mechanisms](/eudiw-connector/explanations/trust-revocation/revocation-mechanisms.md) — explains both credential revocation (Status List) and certificate revocation (CRL). * **Updated:** [Callback events](/eudiw-connector/reference/callback-events.md) — updated credential object field reference. #### June 1, 2026[​](#june-1-2026 "Direct link to June 1, 2026") EUDIW ConnectorAPI v1.2.0 ##### Spec-conformant OID4VCI metadata[​](#spec-conformant-oid4vci-metadata "Direct link to Spec-conformant OID4VCI metadata") The connector's Credential Issuer Metadata and Type Metadata endpoints now conform to [OpenID4VCI 1.0 §12.2](https://openid.net/specs/openid-4-verifiable-credential-issuance-1_0.html), [HAIP 1.0 §3.5](https://openid.net/specs/openid4vc-high-assurance-interoperability-profile-1_0.html), and [SD-JWT VC draft-13 §6.3](https://datatracker.ietf.org/doc/html/draft-ietf-oauth-sd-jwt-vc-13#section-6.3). Wallets that implement these specifications now render credential display names and claim labels correctly. Previously, the metadata used a pre-draft shape that strict wallet deserialisers rejected, causing wallets to fall back to displaying the raw `vct` URL as the credential title and attribute keys as claim labels. ##### API[​](#api-1 "Direct link to API") * **Changed:** Credential Issuer Metadata (`GET /.well-known/openid-credential-issuer`) now nests `display` and `claims` inside a `credential_metadata` object on each credential configuration, instead of placing `display` at the configuration root. * **Changed:** The Type Metadata endpoint (`GET /oidc4vci/types/{credential_configuration_id}`) now serves the document in SD-JWT VC draft-13 array-form with `display[{lang, name}]` and `claims[{path[], sd, display[]}]`. ##### Configuration[​](#configuration-1 "Direct link to Configuration") * **Changed:** Type Metadata JSON files now use the SD-JWT VC draft-13 array-form schema. The `display` field is an array with `lang` and `name` entries, and `claims` is an array of objects with `path`, `sd`, and `display` fields. See [Configure credential types](/eudiw-connector/how-to-guides/credential-type-configuration.md) for the full format reference. ##### Documentation[​](#documentation-2 "Direct link to Documentation") * **Updated:** [Configure credential types](/eudiw-connector/how-to-guides/credential-type-configuration.md) — updated Type Metadata input format and Credential Issuer Metadata output example to reflect the array-form schema. * **Updated:** [Issue a credential quickstart](/eudiw-connector/getting-started/issue-credentials.md) — updated Type Metadata example to use array-form. #### May 21, 2026[​](#may-21-2026 "Direct link to May 21, 2026") EUDIW ConnectorAPI v1.1.0 ##### Credential issuance documentation[​](#credential-issuance-documentation "Direct link to Credential issuance documentation") The Truvity EUDIW Connector now supports credential issuance via the [OpenID for Verifiable Credential Issuance (OID4VCI)](/eudiw-connector/explanations/standards/oid4vci-protocol.md) protocol using the pre-authorized code flow. The connector handles the issuance protocol exchange, token management, [DPoP](/eudiw-connector/explanations/privacy-security/dpop.md) validation, credential signing, and callback-based outcome delivery. ##### API[​](#api-2 "Direct link to API") * **New:** `POST /offers`—create credential offers with `credential_configuration_id`, `claims`, and optional `tx_code` for transaction authorization. Returns `offer_id`, `credential_offer_uri`, and optionally `tx_code_value`. * **New:** Issuance callback delivery via [Issuance Event](/eudiw-connector/reference/callback-events.md) with four statuses: `OFFER_CREATED`, `ISSUED`, `FAILED`, and `EXPIRED`. * **New:** Public OID4VCI protocol endpoints for wallet interaction: credential issuer metadata (`GET /.well-known/openid-credential-issuer`), nonce endpoint, and credential endpoint. ##### Documentation[​](#documentation-3 "Direct link to Documentation") * **New:** [Issue a credential quickstart](/eudiw-connector/getting-started/issue-credentials.md)—first credential offer and callback handling * **New tutorial:** [Build an AOC issuance flow](/eudiw-connector/tutorials/aoc-issuance-tutorial.md)—end-to-end tutorial for issuing Account Ownership Credentials * **New guide:** [Issue a credential](/eudiw-connector/how-to-guides/credential-issuance.md)—how-to for issuing any credential type * **New guide:** [Configure credential types](/eudiw-connector/how-to-guides/credential-type-configuration.md)—set up Type Metadata for credential types * **New guide:** [Use transaction codes](/eudiw-connector/how-to-guides/tx-code.md)—add tx\_code authorization to issuance flows * **New guide:** [Implement AOC issuance](/eudiw-connector/how-to-guides/integration-scenarios/aoc-issuance.md)—production-ready AOC issuance in a banking app * **New guide:** [Verify a credential](/eudiw-connector/how-to-guides/credential-verification.md)—how-to for verifying any credential type * **New explanation:** [OID4VCI protocol](/eudiw-connector/explanations/standards/oid4vci-protocol.md)—how the issuance protocol works * **New explanation:** [DPoP and sender-constrained tokens](/eudiw-connector/explanations/privacy-security/dpop.md)—token security during issuance * **New explanation:** [AOC issuance use case](/eudiw-connector/explanations/use-cases/aoc-issuance.md)—business context for Account Ownership Credential issuance * **Updated:** [HAIP](/eudiw-connector/explanations/standards/haip.md)—added OID4VCI issuance constraints * **Updated:** [Verify a credential quickstart](/eudiw-connector/getting-started/verify-credentials.md)—renamed from "Getting started," streamlined for the two-quickstart structure * **Updated:** Existing reference pages ([callback events](/eudiw-connector/reference/callback-events.md), [error codes](/eudiw-connector/reference/error-codes.md), [glossary](/eudiw-connector/reference/glossary.md), [certificates](/eudiw-connector/how-to-guides/certificates.md), [error handling](/eudiw-connector/how-to-guides/error-handling.md)) with issuance-related content #### April 8, 2026[​](#april-8-2026 "Direct link to April 8, 2026") EUDIW ConnectorAPI v1.0.0 ##### Introducing the Truvity EUDIW Connector[​](#introducing-the-truvity-eudiw-connector "Direct link to Introducing the Truvity EUDIW Connector") The Truvity EUDIW Connector is now available. It is an API-first solution for requesting and verifying digital credentials from EU Digital Identity Wallets (EUDI Wallets). The connector implements the [OpenID for Verifiable Presentations (OID4VP)](/eudiw-connector/explanations/standards/oid4vp-protocol.md) protocol under the [High Assurance Interoperability Profile (HAIP)](/eudiw-connector/explanations/standards/haip.md), handling cryptographic operations, credential verification, and [eIDAS 2.0](/eudiw-connector/explanations/standards/eidas-2-requirements.md) alignment on your behalf. Start with the [verification quickstart](/eudiw-connector/getting-started/verify-credentials.md) or read [What is the EUDIW Connector?](/eudiw-connector/overview/what-is-eudiw-connector.md) for a product overview. ##### API[​](#api-3 "Direct link to API") * **New:** `POST /oidc4vp` — create presentation requests using [DCQL](/eudiw-connector/explanations/standards/dcql.md) queries with [selective disclosure](/eudiw-connector/explanations/privacy-security/selective-disclosure.md). Returns `state`, `same_device_request_uri`, and `cross_device_request_uri` for [same-device and cross-device flows](/eudiw-connector/overview/what-is-eudiw-connector.md#same-device-and-cross-device-flows). * **New:** Callback-based result delivery via [Presented Credentials Event](/eudiw-connector/reference/callback-events.md) with five statuses: `FULFILLED`, `REJECTED`, `EXPIRED`, `PROCESSING_ERROR`, and `VERIFICATION_FAILED`. * **New:** [Transactional data](/eudiw-connector/how-to-guides/transactional-data.md) binding (`transaction_data` parameter) for cryptographic proof of user consent to a specific context. * **New:** [Key binding](/eudiw-connector/explanations/privacy-security/key-binding.md) enforcement (`require_cryptographic_holder_binding` parameter) with stable wallet-derived identifiers (`kbKeyId`). * **New:** Configurable session expiration (`expires_in` parameter). * **New:** SD-JWT and SD-JWT+KB credential format support (`dc+sd-jwt`). ##### Documentation[​](#documentation-4 "Direct link to Documentation") The full EUDIW Connector documentation is now available at [/eudiw-connector](/eudiw-connector/overview/what-is-eudiw-connector.md), covering: * [Getting started](/eudiw-connector/getting-started/verify-credentials.md) — first presentation request and callback handling * Tutorials — complete walkthroughs for [KYC verification](/eudiw-connector/tutorials/kyc-tutorial.md) and [passwordless authentication](/eudiw-connector/tutorials/auth-tutorial.md) * [How-to guides](/eudiw-connector/how-to-guides/certificates.md) — integration scenarios, certificates, error handling, transactional data, and [production readiness](/eudiw-connector/how-to-guides/going-to-production.md) * [Explanations](/eudiw-connector/explanations/architecture/connector-architecture.md) — architecture, standards (OID4VP, DCQL, HAIP, ARF, eIDAS 2.0), privacy and security, trust and revocation, and credential formats * [Reference](/eudiw-connector/reference/callback-events.md) — callback events, error codes, and glossary #### February 9, 2026[​](#february-9-2026 "Direct link to February 9, 2026") SSI PlatformTypeScript SDK v0.40.13 ##### Schema management support for the TypeScript SDK[​](#schema-management-support-for-the-typescript-sdk "Direct link to Schema management support for the TypeScript SDK") This release brings full credential schema management support to the TypeScript SDK, completing the feature set [introduced with the Java SDK on November 27, 2025](#november-27-2025). You can now define, publish, and version credential schemas directly from your TypeScript applications. Get started with the [Schema Management Overview](/ssi/schemas.md) and dive into [Managing Schemas](/ssi/schemas/manage-schemas/create-schema.md). ##### SDK[​](#sdk "Direct link to SDK") ###### TypeScript SDK[​](#typescript-sdk "Direct link to TypeScript SDK") * **New:** Full support for credential schema management capabilities: * Methods for creating, publishing, and versioning schemas * `VcDecorator.publishSchema()` method for making schemas production-ready * Enhanced schema referencing when creating drafts * **New:** Schema definition decorators: * `@VcSchema` - Define schemas, specify publication settings (slug and version), and associate them with user-defined types (UDTs). [Learn more](/ssi/schemas/manage-schemas/create-schema.md) * `@VcExternalSchema` - Reference external JSON-LD vocabularies and JSON schemas for interoperability with other SSI ecosystems. [Learn more](/ssi/schemas/manage-schemas/use-external-schema.md) * **Deprecation:** The `@VcContext` decorator. We will remove this in a future release. Migrate to `@VcSchema` for improved schema management. ##### Migration to version 0.40.13[​](#migration-to-version-04013 "Direct link to Migration to version 0.40.13") Follow these steps to migrate your TypeScript SDK-based integration: ###### 1. Update your SDK version[​](#1-update-your-sdk-version "Direct link to 1. Update your SDK version") Upgrade to SDK version `0.40.13` or higher: ```bash npm install @truvity/sdk@0.40.13 ``` tip The SDK automatically enables backward compatibility for versions lower than `v0.40.0`. Existing applications will continue to work during the migration period. ###### 2. Update decorator usage[​](#2-update-decorator-usage "Direct link to 2. Update decorator usage") **Replace `@VcContext` with `@VcSchema`:** ```diff - @VcContext({ name: 'Passport', namespace: 'urn:example' }) + @VcSchema() class Passport { @VcNotEmptyClaim passportNumber!: string; nationality?: string; } ``` **If using search capability:** if your app searches for credentials by context name, temporarily add the `@VcSchemaJsonLdTermName` decorator to maintain compatibility while you transition to published schemas: ```diff @VcSchema() + @VcSchemaJsonLdTermName('Passport') class Passport { @VcNotEmptyClaim passportNumber!: string; nationality?: string; } ``` note The `@VcSchemaJsonLdTermName` decorator preserves the JSON-LD term name for backward compatibility. Once you publish your schema, you can remove this decorator as the published schema includes the term definition. ###### 3. Update async method calls[​](#3-update-async-method-calls "Direct link to 3. Update async method calls") Several `VcDecorator` methods are now asynchronous. Add `await` to the following calls: **`getCredentialTerm()`** - used when searching for credentials by type: ```diff data: { type: { operator: 'IN', - values: [purchaseRequest.getCredentialTerm()], + values: [await purchaseRequest.getCredentialTerm()], }, }, ``` **`map()`** - used when converting API resources to user-defined types: ```diff - const purchaseRequestVc = purchaseRequest.map(item); + const purchaseRequestVc = await purchaseRequest.map(item); ``` ###### 4. Publish your schemas[​](#4-publish-your-schemas "Direct link to 4. Publish your schemas") For production deployments, publish your schemas to ensure immutability and verifiability: ```typescript const passport = client.vcDecorator(Passport); // Publish the schema await passport.publishSchema(); ``` Learn more about schema publication and versioning in the [Publication and Versioning guide](/ssi/schemas/core-concepts/publication-and-versioning.md). Demo application For a complete working example of publishing schemas and migrating to `@VcSchema`, see the [updated DIF Hackathon demo application](https://github.com/truvity/dif-hackathon-2024-demo/pull/5). #### November 27, 2025[​](#november-27-2025 "Direct link to November 27, 2025") SSI PlatformAPI v0.40.11, Java SDK v0.40.11 ##### Introducing credential schema management[​](#introducing-credential-schema-management "Direct link to Introducing credential schema management") This release introduces a comprehensive suite of tools to manage the entire lifecycle of your credential structures. Credential schemas act as immutable blueprints for your data, ensuring consistency across your ecosystem and facilitating interoperability with external partners. With this release, you can now: * **Define** schemas once and use them across different credential formats * **Publish** schemas to make them publicly verifiable and discoverable * **Version** your data models to evolve them over time without breaking existing credentials Get started with the [Schema Management Overview](/ssi/schemas.md) and dive into [Managing Schemas](/ssi/schemas/manage-schemas/create-schema.md). ##### Breaking changes[​](#breaking-changes "Direct link to Breaking changes") This release introduces several breaking changes to improve schema management and support multiple credential formats: 1. **Structured claim values**: The `values` property in drafts now uses a structured format (`CredentialClaimValues`) with type hints instead of accepting arbitrary data. This resolves serialization and deserialization issues when working with different credential formats and ensures type safety. 2. **Renamed schema model**: We replaced the `DraftSchema` model with `ClaimsSchema`. While structurally similar, `ClaimsSchema` uses clearer, less ambiguous parameter names to better support multiple credential formats. 3. **Schema reference updates**: We renamed the `schema` property in draft creation requests to `meta_schema`. This property now accepts either: * Schema definitions (`MetaSchema`) for temporary schemas during development * URLs to published schemas for production use Backward compatibility To avoid disruption from the introduced breaking changes, we support the previous version of the API (`v0.38.0`) alongside the new version to provide a migration period. If you use one of the SDKs (TypeScript or Java), it automatically enables backward compatibility for all versions lower than `v0.40.0`. You do not need to take any action. If you use the API directly, include the HTTP header `X-Truvity-OAS-Version: 0.38.2` in all requests to enable backward compatibility. Deprecation timeline We will support the old version of the API for up to 3 months. We encourage all customers to update their integrations to the latest version during this period. Read the migration guide [here](#migration-to-version-040xx). warning We may decommission the old API sooner if all active customers migrate before the 3-month period ends. ##### API[​](#api-4 "Direct link to API") * **New:** [Credential Schemas API](/ssi/api-reference.md#tag/schemas) for managing, versioning, and publishing [credential schemas](/ssi/overview/core-concepts/credential-schemas.md). Key operations include: * `POST /schemas` ([SchemaCreate](/ssi/api-reference.md#tag/schemas/operation/SchemaCreate)) - Create schema definitions * `PATCH /schemas/{id}/publish` ([SchemaPublish](/ssi/api-reference.md#tag/schemas/operation/SchemaPublish)) - Publish schemas to make them immutable and publicly verifiable * `POST /schemas/search` ([SchemaSearch](/ssi/api-reference.md#tag/schemas/operation/SchemaSearch)) - Search for schemas * `POST /published-schemas/search` ([PublishedSchemaSearch](/ssi/api-reference.md#tag/published-schemas/operation/PublishedSchemaSearch)) - Search for published schemas * **New:** `GET /credentials/{id}/values` ([GetCredentialClaimValues](/ssi/api-reference.md#tag/credentials/operation/GetCredentialClaimValues)) - Retrieve claim values from issued credentials in a unified, format-independent structure (matching the structure used for draft values). ##### SDK[​](#sdk-1 "Direct link to SDK") ###### Java SDK[​](#java-sdk "Direct link to Java SDK") * **New:** Full support for credential schema management capabilities: * Methods for creating, publishing, and versioning schemas * `VcDecorator.publishSchema()` method for making schemas production-ready * Enhanced schema referencing when creating drafts * **New:** Schema definition decorators: * `@VcSchema` - Define schemas, specify publication settings (slug and version), and associate them with user-defined types (UDTs). [Learn more](/ssi/schemas/manage-schemas/create-schema.md) * `@VcExternalSchema` - Reference external JSON-LD vocabularies and JSON schemas for interoperability with other SSI ecosystems. [Learn more](/ssi/schemas/manage-schemas/use-external-schema.md) * **Deprecation:** The `@VcContext` decorator. We will remove this in a future release. Migrate to `@VcSchema` for improved schema management. * **Fix:** API error responses now properly display human-readable error messages instead of object hashes. ###### TypeScript SDK[​](#typescript-sdk-1 "Direct link to TypeScript SDK") * **Note:** Full support for the new schema management is now available. See the [February 9, 2026 release](#february-9-2026). ##### Documentation[​](#documentation-5 "Direct link to Documentation") * **New section:** [Schema Management](/ssi/schemas.md) - Comprehensive documentation covering the meta-schema model, temporary vs. stable schemas, publication lifecycle, and schema governance principles. * **New guides:** * [Quickly prototype schemas](/ssi/schemas/how-to-guides/prototype-schemas-quickly.md) - Step-by-step guide for rapid schema development and testing using the SDK. * [Build an app for end-users to manage schemas](/ssi/schemas/how-to-guides/build-app-for-end-users-to-manage-schemas.md) - Build applications that allow end-users to create and manage their own schemas programmatically. ##### Migration to version 0.40.XX[​](#migration-to-version-040xx "Direct link to Migration to version 0.40.XX") ###### For direct API users[​](#for-direct-api-users "Direct link to For direct API users") Follow these steps to update your API integration: ###### 1. Update draft value structure[​](#1-update-draft-value-structure "Direct link to 1. Update draft value structure") **What changed:** the `values` property now requires a structured format with explicit type information. **Action required:** instead of passing arbitrary JSON objects, wrap each claim value with type information: ```json { "values": { "firstName": { "kind": "STRING", "value": "John" }, "age": { "kind": "NUMBER", "value": 30 } } } ``` This applies to: * `POST /drafts` ([DraftCreate](/ssi/api-reference.md#tag/drafts/operation/DraftCreate)) - `DraftCreateRequest.data.values` * `PATCH /drafts/{id}` ([DraftUpdate](/ssi/api-reference.md#tag/drafts/operation/DraftUpdate)) - `DraftUpdateRequest.data.values` * `ResourceDraft.data.values` (in all draft-related API responses) ###### 2. Update schema references in drafts[​](#2-update-schema-references-in-drafts "Direct link to 2. Update schema references in drafts") **What changed:** we restructured schema management to support both temporary and published schemas. **`ResourceDraft.data` changes:** * **Removed:** `schema` property * **Added:** * `meta_schema: string` - URL reference to a published schema * `json_ld_vocabs: string[]` - JSON-LD vocabulary URLs for semantic definitions * `vcdm_json_schemas: string[]` - JSON Schema URLs for validation (following the W3C [`vc-json-schema`](https://www.w3.org/TR/vc-json-schema/) specification) **`DraftCreateRequest.data` changes:** * **Added:** * `meta_schema?: string` - URL of a published schema. **Required** unless you use the `schema` property for temporary schemas. * `json_ld_vocabs?: string[]` - Override or supplement JSON-LD vocabularies from the published schema. Enables mixing platform and external vocabularies. Example: ```json "json_ld_vocabs": [ "https://ssi.truvity.com/tenants/123/vocab/passport/v1", "https://www.w3.org/ns/credentials/examples/v2" ] ``` * `vcdm_json_schemas?: string[]` - Override JSON Schema validation from the published schema. Useful for external schemas or custom validation rules not supported by the meta-schema. * **Updated:** * `schema` - Now optional (type changed from required `DraftSchema` to optional `{ schema: ClaimsSchema, slug?, version? }`). Use this for [temporary schemas](/ssi/schemas/core-concepts/temp-and-stable-schemas.md) during development. You must provide either `schema` or `meta_schema`. ###### 3. Update search operations[​](#3-update-search-operations "Direct link to 3. Update search operations") The `POST /drafts/search` ([DraftSearch](/ssi/api-reference.md#tag/drafts/operation/DraftSearch)) operation now returns draft resources using the structure described above. Update your response parsing logic accordingly. ###### For SDK users (Java)[​](#for-sdk-users-java "Direct link to For SDK users (Java)") Follow these steps to migrate your SDK-based integration: ###### 1. Update your SDK version[​](#1-update-your-sdk-version-1 "Direct link to 1. Update your SDK version") Upgrade to SDK version `0.40.0` or higher: ```xml {/* Maven */} com.truvity sdk 0.40.11 ``` tip The SDK automatically enables backward compatibility for versions lower than `v0.40.0`. Existing applications will continue to work during the migration period. ###### 2. Update decorator usage[​](#2-update-decorator-usage-1 "Direct link to 2. Update decorator usage") **Replace `@VcContext` with `@VcSchema`:** ```diff - @VcContext(name = "Passport", namespace = "urn:example") + @VcSchema class Passport { @NotEmpty String passportNumber; String nationality; } ``` **If using search capability:** if your app searches for credentials by context name, temporarily add the `@VcSchemaJsonLdTermName` decorator to maintain compatibility while you transition to published schemas: ```diff @VcSchema + @VcSchemaJsonLdTermName("Passport") class Passport { @NotEmpty String passportNumber; String nationality; } ``` note The `@VcSchemaJsonLdTermName` decorator preserves the JSON-LD term name for backward compatibility. Once you publish your schema, you can remove this decorator as the published schema includes the term definition. ###### 3. Publish your schemas[​](#3-publish-your-schemas "Direct link to 3. Publish your schemas") For production deployments, publish your schemas to ensure immutability and verifiability: ```java VcDecorator passportDecorator = client.vcDecorator(Passport.class); // Publish the schema passportDecorator.publishSchema(); ``` Learn more about schema publication and versioning in the [Publication and Versioning guide](/ssi/schemas/core-concepts/publication-and-versioning.md). --- ## Eudiw Connector ### Introduction to Truvity EUDIW Connector Truvity EUDIW Connector is an API-first solution for verifying and issuing digital credentials with EU Digital Identity Wallets (EUDI Wallets). The connector is available as a Dedicated deployment (managed by Truvity) or Self-managed (operated by you). In both models, your organization acts as the Relying Party (for verification) or credential issuer (for issuance) directly. The connector handles the complexity of implementing the OpenID for Verifiable Presentations (OID4VP) and OpenID for Verifiable Credential Issuance (OID4VCI) protocols, eIDAS 2.0 requirements, and cryptographic certificate management, allowing you to focus on your business logic. #### Start here[​](#start-here "Direct link to Start here") **New to EUDI Wallets?** * **[What is the EUDIW Connector?](/eudiw-connector/overview/what-is-eudiw-connector.md)**—Product introduction, key capabilities, deployment models, and supported credential formats. * **[EUDI Wallet ecosystem context](/eudiw-connector/overview/ecosystem-context.md)**—Understand the Triangle of Trust, key roles (issuers, holders, verifiers), and how Truvity fits into the broader digital identity landscape. * **[Compliance and regulations](/eudiw-connector/overview/compliance-regulations.md)**—eIDAS 2.0 requirements, Architecture Reference Framework (ARF), and your compliance responsibilities. * **[Use cases](/eudiw-connector/overview/use-cases.md)**—Real-world scenarios enabled by EUDI Wallets. **Ready to build?** * **[Verify a credential](/eudiw-connector/getting-started/verify-credentials.md)**—Create your first presentation request. * **[Issue a credential](/eudiw-connector/getting-started/issue-credentials.md)**—Create your first credential offer. * **[Implement KYC verification](/eudiw-connector/how-to-guides/integration-scenarios/kyc-verification.md)**—Task-oriented guide for verifying customer identity using PID credentials. * **[Build a KYC verification flow](/eudiw-connector/tutorials/kyc-tutorial.md)**—Step-by-step tutorial that walks you through a complete integration. #### Further reading[​](#further-reading "Direct link to Further reading") * [Connector architecture](/eudiw-connector/explanations/architecture/connector-architecture.md)—How the connector processes credentials and delivers results * [Glossary](/eudiw-connector/reference/glossary.md)—Definitions for key terms used throughout the documentation --- ### Connector architecture The Truvity EUDIW Connector enables your organization to verify and issue credentials in the EUDI Wallet ecosystem. It abstracts the complexity of the [OID4VP](/eudiw-connector/explanations/standards/oid4vp-protocol.md) and [OID4VCI](/eudiw-connector/explanations/standards/oid4vci-protocol.md) protocols, cryptographic operations, and trust management, allowing your systems to request, verify, and issue digital credentials through a management API. Your organization acts as the **Relying Party (RP)** for verification and as a **credential issuer** for issuance. You own the registration with member state authorities, manage your certificates, and control all data processing. The connector handles protocol implementation, credential verification and signing, and delivers results to your callback endpoint. #### Network architecture[​](#network-architecture "Direct link to Network architecture") The connector exposes two separate network interfaces with distinct security profiles: * **Public-facing interface**: Handles wallet protocol interactions. EUDI Wallets connect to these endpoints for verification (retrieving authorization requests and submitting presentation responses) and for issuance (discovering issuer metadata, requesting nonces, and obtaining credentials). This interface is exposed to the internet. * **Internal management interface**: Provides the API your systems use to create presentation requests and credential offers. This interface is accessible only within your internal network. This separation ensures that wallet-facing protocol endpoints are isolated from your management operations, reducing the attack surface. #### System components[​](#system-components "Direct link to System components") The connector consists of the following components, spanning both verification and issuance: ##### Management API[​](#management-api "Direct link to Management API") A protected API on the internal interface that your systems use to operate the connector. Through this API you create presentation requests for verification and credential offers for issuance. The management API is the single integration point for both flows. ##### Public OID4VP endpoints[​](#public-oid4vp-endpoints "Direct link to Public OID4VP endpoints") Publicly accessible endpoints on the public-facing interface that EUDI Wallets interact with during verification. These handle the protocol handshake described in the [OID4VP standard](/eudiw-connector/explanations/standards/oid4vp-protocol.md): the wallet retrieves the signed authorization request and submits the encrypted presentation response. ##### Public OID4VCI endpoints[​](#public-oid4vci-endpoints "Direct link to Public OID4VCI endpoints") Publicly accessible endpoints on the public-facing interface that EUDI Wallets interact with during issuance. These handle the [OID4VCI protocol](/eudiw-connector/explanations/standards/oid4vci-protocol.md) flow: the wallet discovers credential issuer metadata, requests nonces, and submits credential requests. The connector serves metadata that describes its issuer capabilities and the credential types it supports. ##### Authorization server integration[​](#authorization-server-integration "Direct link to Authorization server integration") The connector integrates with an authorization server that manages the [OAuth 2.0](https://datatracker.ietf.org/doc/html/rfc6749) token lifecycle during issuance. The authorization server owns the token endpoint and handles pre-authorized code management, [DPoP](/eudiw-connector/explanations/privacy-security/dpop.md) validation (per [RFC 9449](https://datatracker.ietf.org/doc/html/rfc9449)), and transaction code validation. The wallet discovers the authorization server through its metadata endpoint and exchanges pre-authorized codes for sender-constrained access tokens. ##### Verification engine[​](#verification-engine "Direct link to Verification engine") The core logic that processes incoming credentials during verification. The connector delegates credential parsing and validation to a dedicated verification component. From your perspective this is a single logical component. The verification engine performs: * **Decryption**: Using ephemeral keys generated for each individual request. * **Protocol verification**: Validating the OID4VP structure, nonce, and state. * **Credential verification**: Checking signatures, validity periods, and [revocation status](/eudiw-connector/explanations/trust-revocation/revocation-mechanisms.md). * **Device binding**: Verifying that the wallet holder controls the credential (see [Device binding](/eudiw-connector/explanations/privacy-security/key-binding.md)). ##### Credential signing[​](#credential-signing "Direct link to Credential signing") The core logic that produces credentials during issuance. When the wallet submits a valid credential request with a key proof, the connector signs the credential using the issuer signing certificate and returns it to the wallet. The signing component binds the credential to the wallet's key, ensuring only the intended holder can present it. #### Session storage[​](#session-storage "Direct link to Session storage") The connector maintains temporary session data for each active verification or issuance flow. Verification sessions track the state of a presentation request from creation through wallet interaction to result delivery. Issuance sessions track the state of a credential offer through the token exchange, credential request, and signing phases. Sessions are automatically cleaned up after they complete or expire. For issuance, credential claims are purged from the session when the flow fails or the session expires. After successful issuance, claims persist until the session TTL expires to support repeated credential requests (per OID4VCI Section 14.3). Session expiry is detected lazily at request time. For details on the connector's data retention approach, see [The ephemeral data model](/eudiw-connector/explanations/privacy-security/ephemeral-data-model.md). No user credential data persists in the connector beyond the lifetime of a session. #### Data flow[​](#data-flow "Direct link to Data flow") Interactions with EUDI Wallets are asynchronous. The user must open their wallet, authenticate, and consent. The connector uses a callback-based event model to handle both verification and issuance flows. ##### Verification data flow[​](#verification-data-flow "Direct link to Verification data flow") ##### Issuance data flow[​](#issuance-data-flow "Direct link to Issuance data flow") The issuance flow follows the [OID4VCI protocol](/eudiw-connector/explanations/standards/oid4vci-protocol.md) using the pre-authorized code grant. Your backend creates a credential offer through the management API. The connector coordinates with the authorization server to generate a pre-authorized code and returns a credential offer URI that you display to the user. The wallet discovers the connector's issuer metadata and the authorization server metadata, exchanges the pre-authorized code for a sender-constrained access token using [DPoP](/eudiw-connector/explanations/privacy-security/dpop.md) ([RFC 9449](https://datatracker.ietf.org/doc/html/rfc9449)), requests a nonce, and submits a credential request with a key proof. The connector signs the credential, delivers it to the wallet, and sends an issuance callback to your backend. Claims persist in the session until the session TTL expires, supporting repeated credential requests per OID4VCI Section 14.3. ##### Callback delivery[​](#callback-delivery "Direct link to Callback delivery") The connector delivers callback events to your endpoint during both verification and issuance flows. For verification, the connector delivers a Presented Credentials Event at the end of the presentation flow, containing the verification result and, for successful verifications, the verified credential data. See [Presented Credentials Event statuses](/eudiw-connector/reference/callback-events.md) for the possible outcomes. For issuance, the connector delivers Issuance Events at multiple points during the flow. An OFFER\_CREATED event confirms the offer was created and the session is active. Terminal events indicate the final outcome: ISSUED (credential successfully delivered to the wallet), FAILED (issuance failed, with error details describing the reason), or EXPIRED (the session expired before the wallet completed the flow). See [Issuance Event statuses](/eudiw-connector/reference/callback-events.md) for details. For verification, callback delivery is synchronous with the wallet response. The connector delivers the callback before responding to the wallet. If callback delivery fails after all retry attempts, the connector returns an error to the wallet. This means a slow or failing callback handler causes the wallet to receive an error response—design your verification callback handler to respond quickly. For issuance, callback delivery is fire-and-forget. The connector sends the callback but does not block the wallet interaction on delivery success. If callback delivery fails, the error is logged but the issuance flow continues normally. * **Event-driven**: Your system does not need to poll for results. The connector pushes events to your callback endpoint for both verification and issuance flows. * **No persistence**: For verification, credential data is sent to your callback and then deleted from the connector. For issuance, credential data is delivered to the wallet and the session expires after its TTL; the callback contains only status metadata. * **Retry behavior**: The connector retries delivery on network errors and server errors (HTTP 5xx). It does not retry on client errors (HTTP 4xx). The default is one retry with a two-second timeout per attempt. ##### Transactional data[​](#transactional-data "Direct link to Transactional data") You can optionally include transactional data when creating a presentation request. Transactional data is contextual information included in the request that the wallet displays to the user during the consent step. After the user approves, the wallet cryptographically signs the transactional data through the [device binding](/eudiw-connector/explanations/privacy-security/key-binding.md) mechanism and returns hashes that the Relying Party verifies. This two-step process—request-side inclusion followed by wallet-side signing—provides cryptographic proof that the user approved the specific context. It enables use cases where the user needs to see and explicitly authorize what they are agreeing to (for example, a payment amount or document reference). #### Security architecture[​](#security-architecture "Direct link to Security architecture") The connector implements several security mechanisms aligned with the [Architecture Reference Framework (ARF)](/eudiw-connector/explanations/standards/arf-overview.md). ##### Identity and trust[​](#identity-and-trust "Direct link to Identity and trust") To interact with wallets, the connector must establish a trusted identity using X.509 certificates. For verification, you obtain access certificates from a Certificate Authority (CA) or member state registrar and configure them in the connector at deployment time. Certificate rotation requires updating the deployment configuration and restarting the connector. Every authorization request is signed with the private key associated with your certificate, allowing the wallet to verify your identity before showing the consent screen. For issuance, the connector uses two additional certificate types. The issuer signing certificate signs the credentials delivered to wallets and is included in the credential header so that wallets and other Relying Parties can verify the credential's authenticity. The access certificate for issuance signs the credential issuer metadata, proving the connector's participation in the ecosystem. These certificates use separate keys from each other and from the verification access certificate. For details, see [Certificates in EUDI](/eudiw-connector/explanations/trust-revocation/certificates.md). ##### Ephemeral encryption[​](#ephemeral-encryption "Direct link to Ephemeral encryption") The connector generates a unique encryption key pair for each presentation request. The public key is included in the authorization request sent to the wallet, and the wallet uses it to encrypt the presentation response. The connector decrypts the response using the corresponding private key. After verification completes and the callback is delivered, the ephemeral keys are permanently deleted. For details, see [Encryption key management](/eudiw-connector/explanations/privacy-security/encryption-key-management.md). ##### Privacy by design[​](#privacy-by-design "Direct link to Privacy by design") The connector follows an [ephemeral data model](/eudiw-connector/explanations/privacy-security/ephemeral-data-model.md) as a security architecture choice. For verification, credentials are processed in memory, delivered to your callback, and then deleted. For issuance, claim data provided in the credential offer is purged from the session when the flow fails, and the session itself expires after its TTL—at which point all remaining data is deleted. You cannot retrieve historical verification or issuance results from the connector. This design minimizes the attack surface by ensuring sensitive identity data does not accumulate in storage. #### Further reading[​](#further-reading "Direct link to Further reading") * [OID4VP protocol](/eudiw-connector/explanations/standards/oid4vp-protocol.md)—how the connector implements the OpenID for Verifiable Presentations standard * [OID4VCI protocol](/eudiw-connector/explanations/standards/oid4vci-protocol.md)—how the connector implements the OpenID for Verifiable Credential Issuance standard * [DPoP and sender-constrained tokens](/eudiw-connector/explanations/privacy-security/dpop.md)—how the connector secures token exchanges during issuance * [The ephemeral data model](/eudiw-connector/explanations/privacy-security/ephemeral-data-model.md)—how the connector processes credentials without persistent storage * [Certificates in EUDI](/eudiw-connector/explanations/trust-revocation/certificates.md)—how X.509 certificates establish identity for verification and issuance in the EUDI Wallet ecosystem --- ### SD-JWT VC credential format When a user presents their digital credentials, they shouldn't have to reveal everything on the credential just to prove a single fact. The **SD-JWT VC** (SD-JWT-based Verifiable Credentials) format solves this by allowing holders to share only the specific attributes a Relying Party requests, while keeping everything else private. SD-JWT VC vs SD-JWT SD-JWT VC and SD-JWT are two related but distinct specifications. SD-JWT (RFC 9901) defines the selective disclosure mechanism—the salted-hash technique that enables attribute-level disclosure from a signed JWT. SD-JWT VC (draft-ietf-oauth-sd-jwt-vc-15) builds on that mechanism to define a credential format with attestation metadata, proof mechanisms, and device binding. When this page refers to the credential format, it uses "SD-JWT VC." When it refers to the underlying disclosure mechanism, it uses "SD-JWT." The Truvity EUDIW Connector uses SD-JWT VC as the credential format for remote verification flows. The EUDI ecosystem mandates two attestation formats: SD-JWT VC and ISO/IEC 18013-5 (mDoc). Both can be used for remote presentation flows via OID4VP, while ISO/IEC 18013-5 also supports proximity flows. The connector focuses on SD-JWT VC. The EUDI ecosystem also requires the [HAIP profile](/eudiw-connector/explanations/standards/haip.md) on top of SD-JWT VC to ensure interoperability between Wallet Units and Relying Parties. HAIP constrains the options in SD-JWT VC to specific choices required for the ecosystem. #### Why SD-JWT VC matters[​](#why-sd-jwt-vc-matters "Direct link to Why SD-JWT VC matters") Physical identity documents force an all-or-nothing disclosure. Showing your ID card to prove your age also reveals your name, address, and photo. SD-JWT VC transforms this by enabling granular, attribute-level disclosure. This capability directly supports two core requirements of the EUDI ecosystem: * **Data minimization** (GDPR Article 5(1)(c)): You request only the attributes you need, and the wallet enforces this constraint * **User control** (eIDAS 2.0): Users see exactly what data is requested and must explicitly consent before sharing #### How SD-JWT VC works[​](#how-sd-jwt-vc-works "Direct link to How SD-JWT VC works") An SD-JWT VC credential separates into three conceptual layers. ##### Issuer-signed payload[​](#issuer-signed-payload "Direct link to Issuer-signed payload") The issuer signs a payload that contains two categories of information: attestation metadata and cryptographic digests of attributes. The attestation metadata—such as the issuer identity, attestation type, and validity period—is always visible to the Relying Party. The attribute digests are one-way hashes that enable selective disclosure: the actual attribute values aren't included in the signed payload. Because the issuer signs both the metadata and the digests, they can't be tampered with. Any modification invalidates the signature. ##### Disclosures[​](#disclosures "Direct link to Disclosures") Each sensitive attribute is packaged as a separate disclosure containing a random salt and the attribute value. The issuer provides these disclosures to the holder alongside the signed payload. During presentation, the holder selects which disclosures to include. The connector hashes each received disclosure and compares it against the digests in the signed payload. If they match, the attribute is authentic. ##### Key binding[​](#key-binding "Direct link to Key binding") [Device binding](/eudiw-connector/explanations/privacy-security/key-binding.md) (called "key binding" in the SD-JWT VC specification) proves that the presenter is the legitimate holder of the credential. The issuer embeds the holder's public key in the signed payload. During presentation, the wallet signs a challenge from the connector using the corresponding private key. Device binding is mandatory for PIDs (Personal Identification Data) because they require a high level of assurance. For other SD-JWT VC attestations, device binding is recommended but not mandatory. A Relying Party can request key binding proof via the presentation request, and the connector requests it by default. This mechanism prevents credential theft. Even if an attacker obtains the credential data, they can't present it without the private key stored in the holder's secure hardware. #### Verification process[​](#verification-process "Direct link to Verification process") When the connector receives an SD-JWT VC presentation, it performs a series of checks: 1. **Signature validation**: Confirms the issuer's signature on the payload is authentic 2. **Disclosure matching**: Hashes each received disclosure and verifies it matches a digest in the signed payload 3. **Key binding verification**: Validates the holder's proof of possession using the public key embedded in the credential 4. **Replay protection**: Confirms the presentation is bound to the current session and can't be reused 5. **Transaction binding**: If the request included transactional data, verifies the holder signed over it 6. **Revocation status**: Checks whether the issuer has revoked the credential #### Privacy and security features[​](#privacy-and-security-features "Direct link to Privacy and security features") ##### Unlinkability[​](#unlinkability "Direct link to Unlinkability") Each disclosure includes a unique random salt. This prevents correlation attacks where verifiers could track a user across sessions by comparing identical hashes. With unique salts, the same attribute produces a different hash in every issuance. ##### Transaction binding[​](#transaction-binding "Direct link to Transaction binding") For high-value operations, you can include transactional data in the presentation request (for example, "authorize payment of EUR 50 to Merchant X"). The wallet signs over this data as part of the key binding proof, creating a cryptographic link between the user's consent and the specific action. This prevents a valid presentation from being replayed in a different context. #### Further reading[​](#further-reading "Direct link to Further reading") * [Selective disclosure](/eudiw-connector/explanations/privacy-security/selective-disclosure.md)—how wallets reveal only requested attributes * [Device binding](/eudiw-connector/explanations/privacy-security/key-binding.md)—cryptographic proof of credential possession * [HAIP profile](/eudiw-connector/explanations/standards/haip.md)—the interoperability profile that constrains SD-JWT VC for the EUDI ecosystem --- ### DPoP and sender-constrained tokens When a wallet requests a credential from an issuer, it first obtains an access token from the authorization server. Without additional protection, anyone who intercepts that token could use it to request credentials on the wallet's behalf. **Demonstration of Proof-of-Possession (DPoP)** solves this by binding each access token to a specific cryptographic key held by the wallet. The token becomes useless to any party that doesn't control the corresponding private key. The Truvity EUDIW Connector requires DPoP for all credential issuance flows. The authorization server validates DPoP proofs during token exchange, and the connector validates DPoP-bound tokens during credential requests. Together, these checks ensure that only the wallet that originally requested the token can use it. #### The problem with bearer tokens[​](#the-problem-with-bearer-tokens "Direct link to The problem with bearer tokens") Standard OAuth 2.0 access tokens are bearer tokens—any party that possesses the token can use it. This works well when tokens travel over secure channels and are short-lived, but it creates risk in credential issuance scenarios. If an attacker intercepts a bearer token during an issuance flow, they could present it to the credential endpoint and receive a credential intended for someone else. The issuer has no way to distinguish the legitimate wallet from the attacker, because the token alone is sufficient for access. In a regulated ecosystem like EUDI, where credentials carry legal weight, this risk is unacceptable. #### How DPoP works[​](#how-dpop-works "Direct link to How DPoP works") DPoP replaces bearer tokens with **sender-constrained tokens**—tokens that are cryptographically bound to the wallet that requested them. The mechanism works in two stages. First, when the wallet requests an access token, it generates a DPoP proof: a signed statement demonstrating that the wallet controls a specific key pair. The authorization server verifies this proof and issues an access token bound to that key. The token itself records which key it is bound to, so any party receiving the token can check whether the presenter actually controls the right key. Second, when the wallet uses the access token to request a credential, it includes a fresh DPoP proof alongside the token. The connector verifies that the proof was signed by the same key the token is bound to. If the signatures don't match—because an attacker stole the token but doesn't have the wallet's private key—the request is rejected. #### Security properties[​](#security-properties "Direct link to Security properties") DPoP provides three complementary security guarantees that together make token theft ineffective. * **Token binding**: The access token is cryptographically bound to the wallet's key. The authorization server records this binding when it issues the token, and the connector checks it when the token is presented. A stolen token cannot be used with a different key. * **Replay prevention**: Each DPoP proof includes a unique identifier and a timestamp. The authorization server and the connector reject proofs they have already seen or proofs that are too old. An attacker who captures a DPoP proof cannot replay it later. * **Stolen token mitigation**: Even if an attacker obtains both the access token and a DPoP proof, they cannot generate new proofs for future requests because they don't have the wallet's private key. The stolen token becomes useless after the captured proof expires or is consumed. #### DPoP in the issuance flow[​](#dpop-in-the-issuance-flow "Direct link to DPoP in the issuance flow") DPoP appears at two points in the credential issuance protocol. During **token exchange**, the wallet presents a DPoP proof to the authorization server alongside the pre-authorized code from the credential offer. The authorization server validates the proof and issues a sender-constrained access token. This is the point where the token-to-key binding is established. During the **credential request**, the wallet presents the sender-constrained access token to the connector along with a fresh DPoP proof. The connector validates that the proof was signed by the key bound to the token. Only after this validation does the connector proceed to sign and return the credential. If a server determines that the DPoP proof requires a server-provided nonce, it returns a `use_dpop_nonce` error signaling the wallet to retry with the correct nonce. Per RFC 9449, this can happen at two points: the authorization server returns HTTP 400 at the token endpoint, and the resource server returns HTTP 401 at the credential endpoint. In both cases, the wallet reads the fresh nonce from the `DPoP-Nonce` response header and retries. This additional round trip prevents certain classes of replay attacks where an attacker might try to use a pre-generated proof. #### Specification references[​](#specification-references "Direct link to Specification references") * [RFC 9449 (DPoP)](https://datatracker.ietf.org/doc/html/rfc9449)—Demonstration of Proof-of-Possession at the app layer #### Further reading[​](#further-reading "Direct link to Further reading") * [OID4VCI protocol](/eudiw-connector/explanations/standards/oid4vci-protocol.md)—the credential issuance protocol that uses DPoP for token security * [Device binding](/eudiw-connector/explanations/privacy-security/key-binding.md)—the related concept that binds credentials to the wallet's device during presentation * [Connector architecture](/eudiw-connector/explanations/architecture/connector-architecture.md)—how the connector implements both issuance and verification protocols --- ### Encryption and key management The Truvity EUDIW Connector manages the cryptographic operations required by the EUDI Wallet ecosystem, handling key lifecycles aligned with the [Architecture Reference Framework (ARF)](/eudiw-connector/explanations/standards/arf-overview.md) and the [High Assurance Interoperability Profile (HAIP)](/eudiw-connector/explanations/standards/haip.md). This page explains how the connector manages signing and encryption keys to ensure security, authenticity, and privacy. #### Key types[​](#key-types "Direct link to Key types") The connector uses two distinct key types: one for proving identity (signing) and one for ensuring confidentiality (encryption). ##### Signing identity key[​](#signing-identity-key "Direct link to Signing identity key") The signing identity key (the private key associated with your X.509 access certificate) is a long-lived key that signs authorization requests sent to EUDI Wallets. It identifies your organization as a registered Relying Party. You are responsible for obtaining your access certificate from a Certificate Authority (CA) or member state registrar and configuring the signing identity key in the connector. For details on certificate types and their roles, see [Certificates in EUDI](/eudiw-connector/explanations/trust-revocation/certificates.md). ##### Ephemeral encryption key[​](#ephemeral-encryption-key "Direct link to Ephemeral encryption key") The ephemeral encryption key is a single-use key pair generated for each presentation request. The public key is included in the authorization request sent to the wallet, and the wallet uses it to encrypt the presentation response. The connector decrypts the response using the corresponding private key, then permanently deletes both keys. This per-request approach limits the window of exposure: because each key pair exists only for a single session and is permanently deleted afterward, a compromise of long-term signing keys does not expose past credential presentations. The ephemeral keys used for those sessions no longer exist. The ARF requires that presentation responses are returned in encrypted format. The connector's ephemeral encryption key mechanism implements this requirement, ensuring that credential data is encrypted end-to-end between the wallet and the connector in addition to transport-layer security. #### Encryption flow[​](#encryption-flow "Direct link to Encryption flow") The connector combines transport-layer security with app-level encryption: 1. **Key generation**: When you create a presentation request, the connector generates a unique ephemeral encryption key pair. 2. **Key exchange**: The ephemeral public key is included in the authorization request sent to the wallet. 3. **Encryption**: The EUDI Wallet uses the public key to encrypt the presentation response before sending it back. 4. **Decryption**: The connector decrypts the response using the ephemeral private key. 5. **Deletion**: After verification completes and the [callback](/eudiw-connector/explanations/architecture/connector-architecture.md) is delivered, the ephemeral keys are permanently deleted. #### Key lifecycle[​](#key-lifecycle "Direct link to Key lifecycle") ##### Signing identity key lifecycle[​](#signing-identity-key-lifecycle "Direct link to Signing identity key lifecycle") The signing identity key is long-lived and tied to your organization's X.509 access certificate. You configure it at deployment time and rotate it according to your certificate renewal schedule. ##### Ephemeral encryption key lifecycle[​](#ephemeral-encryption-key-lifecycle "Direct link to Ephemeral encryption key lifecycle") Ephemeral encryption keys are strictly internal to the connector. They are not exposed through the management API. The connector generates them when you create a presentation request and deletes them when the session completes or expires. This aligns with the [ephemeral data model](/eudiw-connector/explanations/privacy-security/ephemeral-data-model.md) design principle. #### Wallet hardware attestations[​](#wallet-hardware-attestations "Direct link to Wallet hardware attestations") Wallet Units use Wallet Unit Attestations (WUAs) to certify their secure hardware properties to the EUDI Wallet ecosystem. However, Wallet Units do not share WUAs with Relying Parties. As a result, the connector does not receive information about the wallet's secure hardware properties during a presentation exchange. #### External keys[​](#external-keys "Direct link to External keys") During verification, the connector also validates keys managed by other participants: * **Issuer keys**: The connector verifies credential signatures against issuer public keys and certificate chains. * **Holder keys**: The connector validates key binding proofs to confirm that the wallet holder legitimately possesses the credential. See [Device binding](/eudiw-connector/explanations/privacy-security/key-binding.md) for details. #### Further reading[​](#further-reading "Direct link to Further reading") * [The ephemeral data model](/eudiw-connector/explanations/privacy-security/ephemeral-data-model.md)—how the connector processes credential data in memory and deletes it after callback delivery * [Device binding](/eudiw-connector/explanations/privacy-security/key-binding.md)—how key binding proves that the entity presenting a credential is its legitimate holder * [OID4VP protocol](/eudiw-connector/explanations/standards/oid4vp-protocol.md)—how the OID4VP protocol enables credential verification between wallets and Relying Parties --- ### The ephemeral data model The Truvity EUDIW Connector uses an ephemeral data model as a security architecture choice that minimizes the attack surface for sensitive identity data. Credential data is processed in memory during verification, delivered to your callback, and then permanently deleted. No user attributes persist in the connector. #### Why ephemeral[​](#why-ephemeral "Direct link to Why ephemeral") Identity verification involves sensitive personal data such as Personal Identification Data (PID). Storing this data creates risk: the longer it persists, the larger the potential impact of a breach. The ephemeral model eliminates this risk by ensuring credential data exists in the connector only for the duration of a single verification flow. This design also aligns with the ARF's unlinkability requirements. The ARF expects Relying Parties to discard unique fixed elements from attestations—such as hash values, salts, public keys, and signatures—as soon as they are no longer needed, to prevent cross-transaction tracking. The connector's automatic deletion after callback delivery satisfies this expectation by design. The ephemeral model simplifies your compliance posture. Because the connector does not retain user data, it reduces the scope of GDPR obligations and security audits related to the verification infrastructure. User approval is not GDPR consent User approval to present attributes from a Wallet Unit does not constitute lawful grounds for data processing under GDPR. You must independently ensure a lawful basis under GDPR Article 6 for processing the personal data you receive through the connector. See [Compliance and regulations](/eudiw-connector/overview/compliance-regulations.md) for more context. #### How the model works[​](#how-the-model-works "Direct link to How the model works") The ephemeral model relies on single-use cryptographic keys and strict lifecycle management. ##### Key generation[​](#key-generation "Direct link to Key generation") When you create a presentation request, the connector generates a unique encryption key pair for that request. The public key is included in the authorization request sent to the wallet. The private key is stored temporarily with the session and used only once to decrypt the wallet's response. ##### In-memory processing[​](#in-memory-processing "Direct link to In-memory processing") When the EUDI Wallet submits a presentation response: 1. The connector retrieves the session's private key. 2. The connector decrypts the wallet's response into memory. 3. Verification (signature checks, trust chain validation, selective disclosure) occurs entirely in memory. ##### Deletion after delivery[​](#deletion-after-delivery "Direct link to Deletion after delivery") After the connector delivers the verification result to your [callback](/eudiw-connector/explanations/architecture/connector-architecture.md): * The presentation request session is deleted. * The ephemeral encryption keys are deleted. * All user attributes and credential data is cleared from memory. #### Session lifecycle[​](#session-lifecycle "Direct link to Session lifecycle") The following diagram illustrates the data lifecycle during a verification flow: #### Automatic session cleanup[​](#automatic-session-cleanup "Direct link to Automatic session cleanup") Sessions that are not completed (for example, the user never responds or the wallet times out) are automatically cleaned up. The connector deletes expired sessions and their associated keys on a regular schedule, ensuring that incomplete flows do not leave data behind. #### Connector as a Relying Party Instance[​](#connector-as-a-relying-party-instance "Direct link to Connector as a Relying Party Instance") The ARF distinguishes between a Relying Party Instance and an intermediary. A Relying Party Instance is a combination of hardware and software that a Relying Party uses to interact with Wallet Units—it is the RP's own technical system. An intermediary is a separate party that offers services to Relying Parties, connecting to Wallet Units on their behalf and forwarding the presented attributes. When you deploy the connector, it operates as your Relying Party Instance. The ephemeral data model is a security architecture choice that minimizes the attack surface for identity data, not a legal obligation imposed by the intermediary data storage restriction in Article 5b(10) of eIDAS 2.0. An organization qualifies as an intermediary when it (a) offers services to other Relying Parties, (b) connects to Wallet Units on their behalf, (c) requests User attributes that those Relying Parties need, and (d) forwards the presented attributes to the intermediated Relying Party. Article 5b(10) requires that intermediaries are deemed to be Relying Parties and must not store data about the content of the transaction. If you deploy the connector within your own infrastructure and interact with Wallet Units directly, you are operating as a Relying Party—not as an intermediary. #### Integration considerations[​](#integration-considerations "Direct link to Integration considerations") ##### Push-only delivery[​](#push-only-delivery "Direct link to Push-only delivery") Because data is deleted after delivery, you cannot retrieve verification results later from the connector. You must implement a callback endpoint to receive results at the time of verification. ##### Callback reliability[​](#callback-reliability "Direct link to Callback reliability") Callback delivery is synchronous with the wallet response. The connector delivers the callback and waits for a result before responding to the wallet. The connector retries on network errors and server errors (HTTP 5xx) but does not retry on client errors (HTTP 4xx). If your callback endpoint is unreachable after all retry attempts, the verification data is lost and the wallet receives an error response. Ensure your callback infrastructure is highly available and responds quickly. ##### GDPR data erasure scope[​](#gdpr-data-erasure-scope "Direct link to GDPR data erasure scope") The ARF enables Users to request data deletion from Relying Parties through their Wallet Unit dashboard, in accordance with GDPR Article 17. Because the connector does not retain user data after callback delivery, these erasure requests apply only to data stored in your own systems after receiving the callback, not to the connector itself. #### Further reading[​](#further-reading "Direct link to Further reading") * [Encryption key management](/eudiw-connector/explanations/privacy-security/encryption-key-management.md)—how the connector manages signing and encryption keys for secure credential verification * [Connector architecture](/eudiw-connector/explanations/architecture/connector-architecture.md)—system components, data flow, and the management API that your app integrates with * [Compliance and regulations](/eudiw-connector/overview/compliance-regulations.md)—eIDAS 2.0 and ARF requirements relevant to EUDIW Connector integrations --- ### Device binding A digital credential is a file. Without additional protection, anyone who obtains a copy could present it as their own. Device binding solves this by cryptographically linking each credential to the Wallet Secure Cryptographic Device (WSCD) in the holder's wallet. Because the WSCD prevents the private key from being extracted or copied, the credential becomes non-transferable. Terminology The Architecture Reference Framework (ARF) uses "device binding" as the primary term. The SD-JWT VC specification calls the same mechanism "key binding." This page uses "device binding" to align with the ARF. #### When device binding applies[​](#when-device-binding-applies "Direct link to When device binding applies") Device binding is mandatory for PIDs (Personal Identification Data), because PIDs require a high level of assurance that in turn requires binding to a WSCD. For other SD-JWT VC attestations, device binding is recommended but not mandatory—an attestation provider may choose not to include it. The Truvity EUDIW Connector requests and verifies device binding proof by default. A Relying Party can indicate in the presentation request whether it requires proof of device binding for a requested attestation. #### How device binding works[​](#how-device-binding-works "Direct link to How device binding works") Device binding relies on asymmetric cryptography across three stages of the credential lifecycle. ##### Issuance[​](#issuance "Direct link to Issuance") When a holder receives a credential, their wallet generates a cryptographic key pair inside the WSCD. The wallet sends the public key to the issuer, who embeds it in the credential and signs the entire package. This binds the public key to the credential's attributes permanently. ##### Storage[​](#storage "Direct link to Storage") The WSCD stores the private key in tamper-resistant hardware (such as a Secure Element or Trusted Execution Environment). This hardware-backed storage ensures the private key cannot be exported or copied, which is the core security guarantee of device binding. ##### Presentation[​](#presentation "Direct link to Presentation") When the holder presents the credential, the wallet proves possession of the private key stored in the WSCD: 1. The connector sends a unique challenge (nonce) in the presentation request 2. The wallet signs this challenge using the private key in the WSCD 3. The connector verifies the signature using the public key embedded in the credential If the signature is valid, the connector confirms the presenter controls the WSCD bound to the credential. An attacker who obtained the credential file would lack access to the WSCD and could not produce a valid signature. #### Verification checks[​](#verification-checks "Direct link to Verification checks") During presentation verification, the connector validates the device binding proof by checking: * **Signature validity**: The proof signature matches the public key embedded in the credential * **Nonce match**: The challenge in the proof matches the nonce from the presentation request, preventing replay attacks * **Audience binding**: The proof is addressed to the correct Relying Party * **Disclosure binding**: The proof is cryptographically tied to the specific attributes disclosed in this session #### Authenticating transactional data[​](#authenticating-transactional-data "Direct link to Authenticating transactional data") Device binding can go beyond proving possession of the WSCD. The same mechanism can authenticate transactional data that a Relying Party includes in the presentation request. For example, in a payment scenario the Relying Party can include the payment amount and payee in the request. The wallet signs this transactional data using the same private key in the WSCD, creating a cryptographic link between the user's consent and the specific transaction details. This extends device binding from a proof of possession into a form of strong customer authentication where the user explicitly authorizes a specific action. See [Use transactional data](/eudiw-connector/how-to-guides/transactional-data.md) for implementation details. #### Recognizing returning users with kbKeyId[​](#recognizing-returning-users-with-kbkeyid "Direct link to Recognizing returning users with kbKeyId") The connector provides a Key Binding Key Identifier (kbKeyId)—an [RFC 7638](https://datatracker.ietf.org/doc/html/rfc7638) JWK Thumbprint derived from the holder's public key. Because the public key remains constant across presentations of the same credential, the kbKeyId provides a consistent way to recognize returning users. Connector-specific feature The kbKeyId is a connector-specific feature, not a concept defined by the ARF. The EUDI ecosystem's privacy model uses mechanisms like short-lived attestations and batch issuance to limit Relying Party linkability. A stable identifier across presentations may conflict with these unlinkability goals, depending on the attestation's re-issuance strategy. You can use the kbKeyId to: * Link a presentation to an existing user account * Recognize a returning user across different sessions * Associate multiple credentials with the same user profile, if the wallet uses the same key pair #### Further reading[​](#further-reading "Direct link to Further reading") * [SD-JWT VC format](/eudiw-connector/explanations/credential-formats/sd-jwt.md)—the credential format that implements device binding (called "key binding" in the specification) * [HAIP profile](/eudiw-connector/explanations/standards/haip.md)—the interoperability profile that requires device binding * [OID4VP protocol](/eudiw-connector/explanations/standards/oid4vp-protocol.md)—the presentation protocol that carries device binding proofs * [Transactional data](/eudiw-connector/how-to-guides/transactional-data.md)—how to authenticate transactional data using device binding --- ### Selective disclosure Physical identity documents force an all-or-nothing disclosure. Showing your ID card to prove your age also reveals your name, address, and photo. Selective disclosure changes this by allowing credential holders to share only the specific attributes a Relying Party requests, while keeping everything else private. The Truvity EUDIW Connector enforces selective disclosure through the [SD-JWT VC](/eudiw-connector/explanations/credential-formats/sd-jwt.md) credential format and [DCQL](/eudiw-connector/explanations/standards/dcql.md) query language. #### How it works[​](#how-it-works "Direct link to How it works") Selective disclosure relies on cryptographic commitments built into the credential at issuance. When an issuer creates a credential, they do not sign the attribute values directly. Instead, each sensitive attribute is wrapped with a random salt and hashed. The issuer signs a payload containing these hashes rather than the raw values. During presentation: * **To disclose an attribute**: The wallet sends both the hash (in the signed payload) and the original value with its salt. The connector hashes the value and confirms it matches the signed hash. * **To withhold an attribute**: The wallet sends the signed payload but omits the value. The connector sees only the hash, which reveals nothing about the underlying data. Because the issuer signed the hashes, the connector can verify that disclosed attributes are authentic without needing to see the withheld ones. note The salted-hash selective disclosure mechanism is not unique to SD-JWT. ISO/IEC 18013-5 (mDoc), the other mandatory attestation format in the EUDI ecosystem, also supports selective disclosure. #### Requesting specific attributes[​](#requesting-specific-attributes "Direct link to Requesting specific attributes") For selective disclosure to work, you must specify exactly which attributes you need. You do this through a [DCQL query](/eudiw-connector/explanations/standards/dcql.md) in your presentation request. The query lists the credential type and the specific attributes required. For example, a bank verifying a customer's identity for account opening might request name and date of birth from a PID credential. The wallet displays this request to the user, who sees exactly what data the bank is asking for. After the user consents, the wallet generates a presentation containing only the requested attributes. All other attributes on the credential remain hidden. The granularity of selective disclosure depends on how the attestation scheme defines attributes. For example, if an attestation scheme defines "address" as a single attribute, you cannot request only the city—the entire address is either shared or withheld. Attestation schemes that break addresses into separate attributes (street, city, postal code) allow finer-grained disclosure. #### Privacy benefits[​](#privacy-benefits "Direct link to Privacy benefits") ##### Data minimization[​](#data-minimization "Direct link to Data minimization") GDPR Article 5(1)(c) requires that personal data collection be "adequate, relevant and limited to what is necessary." Selective disclosure transforms this legal requirement into a technical enforcement. You request only the attributes you need, and the wallet ensures you never receive anything beyond that. ##### Unlinkability[​](#unlinkability "Direct link to Unlinkability") Each attribute disclosure includes a unique random salt. This prevents correlation via the cryptographic digests in the signed payload—with unique salts, the same attribute value produces a different hash in every credential issuance, so Relying Parties cannot compare hashes to track a user across sessions. However, salts do not prevent correlation via the disclosed attribute values themselves. If you disclose the same attribute value (for example, a name) to two Relying Parties, those Relying Parties can still correlate the user by comparing the values they received. The EUDI ecosystem addresses broader Relying Party linkability through additional mechanisms beyond salted hashes, including short-lived attestations (credentials with validity periods brief enough that they expire before meaningful tracking is possible) and batch issuance (issuing multiple instances of the same credential so the holder can use a different instance for each presentation). These mechanisms limit the window during which a given credential can be presented and reduce the ability to correlate presentations over time. #### Further reading[​](#further-reading "Direct link to Further reading") * [SD-JWT VC credential format](/eudiw-connector/explanations/credential-formats/sd-jwt.md)—the credential format that enables selective disclosure * [Digital Credentials Query Language (DCQL)](/eudiw-connector/explanations/standards/dcql.md)—how to specify which attributes to request * [The ephemeral data model](/eudiw-connector/explanations/privacy-security/ephemeral-data-model.md)—how the connector handles disclosed data without persistence --- ### Architecture Reference Framework (ARF) The [eIDAS 2.0 regulation](/eudiw-connector/explanations/standards/eidas-2-requirements.md) establishes what digital identity must achieve in the EU. The **Architecture Reference Framework (ARF)** defines how to achieve it. It translates legal principles into specific technical requirements that wallets, attestation providers, and Relying Parties must implement. The Truvity EUDIW Connector implements the ARF requirements relevant to credential verification, so you can focus on your business logic while the connector handles protocol compliance. #### From legal principles to technical requirements[​](#from-legal-principles-to-technical-requirements "Direct link to From legal principles to technical requirements") The ARF bridges the gap between high-level legal mandates and concrete technical specifications: * **Legal principle** (eIDAS 2.0): Users must control their data and disclose only what is necessary. **Technical requirement** (ARF): Implementations must support [selective disclosure](/eudiw-connector/explanations/privacy-security/selective-disclosure.md) to enable sharing specific attributes without revealing the entire credential. * **Legal principle** (eIDAS 2.0): Relying Parties must be authenticated and authorized. **Technical requirement** (ARF): Relying Parties must use X.509 [access certificates](/eudiw-connector/explanations/trust-revocation/certificates.md) to authenticate themselves to wallets during the presentation flow. This translation ensures that a wallet developed in one member state can interact with a Relying Party in any other member state. #### Key ARF topics for Relying Parties[​](#key-arf-topics-for-relying-parties "Direct link to Key ARF topics for Relying Parties") ##### RP registration and authentication[​](#rp-registration-and-authentication "Direct link to RP registration and authentication") The ARF defines how Relying Parties are identified and trusted by wallets: * **Access certificates**: You authenticate yourself to wallets using X.509 certificates. The connector uses these certificates to sign authorization requests, allowing the wallet to display your verified identity to the user. * **Registration**: In a production environment, you register with member state authorities to obtain these certificates. The connector supports both self-signed certificates for development and CA-issued certificates for production. ##### Relying Party Intermediaries[​](#relying-party-intermediaries "Direct link to Relying Party Intermediaries") The ARF defines the role of a Relying Party Intermediary (RPI)—a party that acts on behalf of Relying Parties to connect to Wallet Units and request attributes. Article 5b(10) of eIDAS 2.0 establishes two binding rules for RPIs: they are deemed to be Relying Parties (with all associated obligations), and they must not store data about the content of the transaction. Separately, the connector uses an [ephemeral data model](/eudiw-connector/explanations/privacy-security/ephemeral-data-model.md) as a security architecture choice that minimizes the attack surface for sensitive identity data. Verification results are delivered through callbacks and not persisted. ##### Presentation protocol[​](#presentation-protocol "Direct link to Presentation protocol") The ARF mandates specific protocols for credential exchange: * **Protocol**: The ecosystem uses [OpenID for Verifiable Presentations (OID4VP)](/eudiw-connector/explanations/standards/oid4vp-protocol.md) * **Profile**: The [High Assurance Interoperability Profile (HAIP)](/eudiw-connector/explanations/standards/haip.md) constrains OID4VP with strict security parameters that the connector implements by default * **Query language**: Requests use [DCQL](/eudiw-connector/explanations/standards/dcql.md) to specify exactly which credentials and attributes are needed * **Flows**: Both same-device and cross-device flows are required ##### Trust evaluation[​](#trust-evaluation "Direct link to Trust evaluation") Verification involves more than checking a signature. The ARF requires comprehensive trust evaluation: * **Chain verification**: Validating the issuer's certificate chain against the [trusted list](/eudiw-connector/explanations/trust-revocation/trust-lists.md) of the relevant member state * **Revocation checking**: Verifying that the credential has not been [revoked](/eudiw-connector/explanations/trust-revocation/revocation-mechanisms.md) by the issuer * **[Device binding](/eudiw-connector/explanations/privacy-security/key-binding.md)**: Verifying that the entity presenting the credential is the legitimate holder #### Connector compliance[​](#connector-compliance "Direct link to Connector compliance") The connector implements ARF requirements so you can focus on your integration logic: | ARF requirement | What the connector handles | | ---------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Protocol implementation** | Implements OID4VP with the HAIP profile, supporting both same-device and cross-device flows | | **Data minimization** | Implements an ephemeral data model. Verification results are delivered through callbacks and not persisted. Ephemeral encryption keys are used per session and deleted afterward | | **Cryptographic operations** | Handles signature validation, key binding verification, and SD-JWT parsing automatically | | **Trust management** | Uses your X.509 certificates for RP authentication and automates issuer trust chain and revocation status validation | | **Query construction** | Provides interfaces to construct DCQL queries for specific credentials and attributes | #### Standards ecosystem[​](#standards-ecosystem "Direct link to Standards ecosystem") The ARF relies on a stack of existing and emerging standards: * **[OID4VP](/eudiw-connector/explanations/standards/oid4vp-protocol.md)**: The transport protocol for requesting and receiving verifiable credentials * **[HAIP](/eudiw-connector/explanations/standards/haip.md)**: A strict security profile ensuring interoperability across the EUDI ecosystem * **[DCQL](/eudiw-connector/explanations/standards/dcql.md)**: The query format for requesting specific credentials and attributes * **[SD-JWT](/eudiw-connector/explanations/credential-formats/sd-jwt.md)**: A credential format that enables selective disclosure and key binding #### Implementing Acts[​](#implementing-acts "Direct link to Implementing Acts") The ARF translates eIDAS 2.0 into technical requirements, but the legally binding rules are formalized in Commission Implementing Regulations (CIRs). Key Implementing Acts relevant to Relying Parties include: * **CIR (EU) 2024/2982**—defines the protocols and interfaces for the EUDI Framework, covering credential issuance, attribute presentation, data erasure requests, and Relying Party reporting to supervisory authorities. * **CIR (EU) 2025/848**—establishes rules for the registration of wallet-relying parties, including requirements for national registers and the information that Relying Parties must provide during registration. * **CIR (EU) 2024/2977**—defines rules for Personal Identification Data (PID) and electronic attestations of attributes (EAA), including attestation formats and issuance requirements. For a complete list of Implementing Acts and their scope, see [compliance and regulations](/eudiw-connector/overview/compliance-regulations.md). #### Further reading[​](#further-reading "Direct link to Further reading") * [eIDAS 2.0 requirements](/eudiw-connector/explanations/standards/eidas-2-requirements.md)—the legal framework that the ARF implements * [Compliance and regulations](/eudiw-connector/overview/compliance-regulations.md)—your compliance responsibilities as a Relying Party * [Connector architecture](/eudiw-connector/explanations/architecture/connector-architecture.md)—how the connector implements ARF requirements --- ### Digital Credentials Query Language (DCQL) When you create a presentation request, you need a precise way to tell the wallet which credentials and attributes you require. **Digital Credentials Query Language (DCQL)** is the standard format for expressing these requirements. It ensures that wallets can evaluate your request unambiguously and display a clear consent screen to the user. DCQL is defined within the [OpenID for Verifiable Presentations 1.0](https://openid.net/specs/openid-4-verifiable-presentations-1_0.html) specification. The Truvity EUDIW Connector uses DCQL as the query language in all [OID4VP](/eudiw-connector/explanations/standards/oid4vp-protocol.md) presentation requests. #### Why DCQL matters[​](#why-dcql-matters "Direct link to Why DCQL matters") Without a standard query format, each wallet and Relying Party would need custom integration logic to interpret credential requests. DCQL solves this by providing a declarative syntax that every compliant implementation understands. A DCQL query specifies: * Which credential types are acceptable (for example, a PID or a custom attestation) * Which specific attributes you need from those credentials * Which combinations of credentials and attributes satisfy the request This structured approach enables wallets to evaluate the request automatically and show users exactly what data is being requested before they consent. #### Core concepts[​](#core-concepts "Direct link to Core concepts") ##### Credential selection[​](#credential-selection "Direct link to Credential selection") A DCQL query identifies which credentials satisfy your requirements by filtering on the credential format and type. For example, you can request a PID in SD-JWT format, and the wallet matches this against the credentials stored on the device. If the wallet holds a matching credential, it proceeds to the disclosure step. If not, it informs the user that the required credential is unavailable. ##### Selective disclosure[​](#selective-disclosure "Direct link to Selective disclosure") A key feature of DCQL is its support for [selective disclosure](/eudiw-connector/explanations/privacy-security/selective-disclosure.md). Rather than requesting an entire credential, you request only the specific attributes you need. For example, if you only need to verify that a user is over 18, you can request just the age verification attribute. The wallet generates a cryptographic proof of that fact without revealing the full date of birth, address, or other personal data. This aligns with the data minimization principles of eIDAS 2.0 and GDPR. ##### Required and optional semantics[​](#required-and-optional-semantics "Direct link to Required and optional semantics") DCQL's query model operates at two levels. At the credential level, you define which credentials are acceptable, for example, a PID or a specific attestation type. At the claim level, you specify which claims to request from each matched credential. The required and optional semantics are more nuanced than a simple per-attribute flag: whether a credential match is required depends on the overall query structure, and individual claims within a credential query control what the wallet discloses from a matched credential. ##### Credential sets[​](#credential-sets "Direct link to Credential sets") DCQL supports defining alternative credential combinations through credential sets. This allows you to specify that a request can be satisfied by different combinations of credentials, for example, "present a PID" or "present a national ID card and a proof of address." Credential sets enable flexible verification flows where multiple credential combinations are acceptable. #### Privacy benefits[​](#privacy-benefits "Direct link to Privacy benefits") DCQL is a critical enabler of data minimization in the EUDI ecosystem: * **Granularity**: You request only the minimum dataset needed for your use case * **Transparency**: The wallet generates a clear consent screen showing exactly what data is requested * **User control**: The user sees and approves each attribute before sharing it #### Transactional data[​](#transactional-data "Direct link to Transactional data") While DCQL selects which credentials and attributes to present, it works alongside transactional data to secure the context of the presentation. When you create a presentation request, you can include both a DCQL query (specifying what data you need) and transactional data (describing the purpose, such as authorizing a specific payment). The wallet displays the transactional data to the user and signs over it, creating a cryptographic binding between the user's consent and the specific action. This prevents a presentation from being replayed in a different context. #### Relationship to other standards[​](#relationship-to-other-standards "Direct link to Relationship to other standards") * **[OID4VP](/eudiw-connector/explanations/standards/oid4vp-protocol.md)**: DCQL is the query language transported within the OID4VP protocol * **[SD-JWT](/eudiw-connector/explanations/credential-formats/sd-jwt.md)**: DCQL's attribute selection maps directly to the selective disclosure capabilities of SD-JWT credentials * **[HAIP](/eudiw-connector/explanations/standards/haip.md)**: The High Assurance Interoperability Profile mandates DCQL as the query language for credential requests in the EUDI ecosystem #### Further reading[​](#further-reading "Direct link to Further reading") * [OID4VP protocol](/eudiw-connector/explanations/standards/oid4vp-protocol.md)—the transport protocol that carries DCQL queries * [Selective disclosure](/eudiw-connector/explanations/privacy-security/selective-disclosure.md)—how wallets reveal only requested attributes * [Use cases](/eudiw-connector/overview/use-cases.md)—business scenarios showing DCQL in action --- ### eIDAS 2.0 requirements If you plan to verify credentials from EU Digital Identity Wallets (EUDI Wallets), you need to understand the legal framework that governs the ecosystem. The **eIDAS 2.0 Regulation** (EU) 2024/1183 establishes the rules for digital identity across the European Union, defining how wallets work, what Relying Parties must do, and how user privacy is protected. The Truvity EUDIW Connector implements the technical requirements derived from eIDAS 2.0, so you can focus on your business logic while the connector handles protocol compliance. #### What eIDAS 2.0 introduces[​](#what-eidas-20-introduces "Direct link to What eIDAS 2.0 introduces") The regulation builds on the original 2014 eIDAS framework to create a unified architecture for digital identity. Key elements include: * **EUDI Wallets**: Personal apps that allow users to store and present digital credentials * **Personal Identification Data (PID)**: The digital equivalent of a national ID card, containing core identity attributes * **Electronic Attestations of Attributes (EAA)**: Verified credentials from trusted sources (for example, driving licenses, diplomas, or bank account proofs) * **Relying Parties (RPs)**: Organizations that request and verify these credentials ##### Core principles[​](#core-principles "Direct link to Core principles") * **User control**: Users must explicitly consent to share data and can choose exactly which attributes to disclose * **Data minimization**: You must request only the data strictly necessary for your specific service * **Privacy by design**: The architecture prevents tracking user behavior across different services * **Cross-border interoperability**: A credential issued in one member state must be accepted by Relying Parties in all other member states #### Key regulations[​](#key-regulations "Direct link to Key regulations") Regulation (EU) 2024/1183 is the core eIDAS 2.0 regulation. It defines the EUDI Wallet, trust services, and the obligations for all ecosystem participants. The Commission has adopted Implementing Regulations that define the technical specifications for the framework: | Regulation | Type | Scope | | ------------------ | ----------------------- | -------------------------------------------------------------------- | | **(EU) 2024/1183** | Core regulation | The eIDAS 2.0 regulation defining the EUDI Wallet and trust services | | **(EU) 2024/2977** | Implementing Regulation | Person identification data and electronic attestations of attributes | | **(EU) 2024/2979** | Implementing Regulation | Integrity and core functionalities of EUDI Wallets | | **(EU) 2024/2980** | Implementing Regulation | Notifications to the Commission concerning the EUDI Wallet ecosystem | | **(EU) 2024/2982** | Implementing Regulation | Protocols and interfaces for the EUDI Framework | | **(EU) 2025/848** | Implementing Regulation | Registration of wallet-relying parties | #### Requirements for Relying Parties[​](#requirements-for-relying-parties "Direct link to Requirements for Relying Parties") Any organization that verifies credentials from an EUDI Wallet must comply with Article 6b and related provisions. ##### Registration and authentication[​](#registration-and-authentication "Direct link to Registration and authentication") To verify credentials, you must register with the relevant member state authority. This involves: * **Declaring intended use**: You specify exactly why you need the data (for example, "age verification for restricted goods") * **Identity verification**: You are identified by valid X.509 certificates * **Access certificates** authenticate you to the wallet during a transaction * **Registration certificates** prove your authorization to request specific data types For details on certificate types and management, see [certificates](/eudiw-connector/explanations/trust-revocation/certificates.md). ##### Transparency and consent[​](#transparency-and-consent "Direct link to Transparency and consent") When you request data, the EUDI Wallet displays a consent screen to the user: * **Identity display**: The user sees your authenticated name, verified through your X.509 certificate * **Purpose display**: The wallet shows the specific reason for the request * **Explicit consent**: The user must actively approve the transaction ##### Data protection[​](#data-protection "Direct link to Data protection") As a Relying Party, you act as a Data Controller under GDPR. Key obligations include: * **Lawful basis**: Establishing a legal basis for processing the requested attributes * **Storage limitation**: Data must not be kept longer than necessary for the service * **Unlinkability**: You should not collude with other parties to track users across contexts #### The intermediary role[​](#the-intermediary-role "Direct link to The intermediary role") The eIDAS 2.0 regulation and the [Architecture Reference Framework (ARF)](/eudiw-connector/explanations/standards/arf-overview.md) define the role of an **intermediary**—a party that acts on behalf of Relying Parties to interact with EUDI Wallets. This documentation uses the term Relying Party Intermediary (RPI) as a shorthand for this role. An intermediary performs all tasks assigned to a Relying Party on behalf of the intermediated RP. This includes registration, wallet authentication, trust evaluation, revocation checking, and all other RP obligations defined in the ARF—not just the technical verification step. When you register with a Registrar, the registration process also records whether you intend to use an intermediary, and if so, which one. ##### The data storage restriction[​](#the-data-storage-restriction "Direct link to The data storage restriction") Article 5b(10) of eIDAS 2.0 establishes a binding restriction on intermediaries: > "Intermediaries acting on behalf of relying parties shall be deemed to be relying parties and shall not store data about the content of the transaction." This provision has two effects. First, intermediaries bear the same legal obligations as Relying Parties. Second, intermediaries must not retain data about the content of the transaction. To comply, an intermediary must operate using an [ephemeral data model](/eudiw-connector/explanations/privacy-security/ephemeral-data-model.md): 1. Receive the encrypted presentation from the wallet 2. Decrypt and verify the data in memory using ephemeral keys 3. Forward the verified data to the Relying Party through a callback 4. Delete the personal data from its system after forwarding ##### Implications for integration[​](#implications-for-integration "Direct link to Implications for integration") The Article 5b(10) data storage restriction shapes how verification systems deliver results. Because an intermediary cannot store transactional data, integrations use callbacks to receive results rather than polling for past records. The connector implements this pattern through the [Presented Credentials Event](/eudiw-connector/reference/callback-events.md), delivering verified attributes to your system after verification completes. #### Further reading[​](#further-reading "Direct link to Further reading") * [Architecture Reference Framework](/eudiw-connector/explanations/standards/arf-overview.md)—the technical blueprint derived from eIDAS 2.0 * [Ephemeral data model](/eudiw-connector/explanations/privacy-security/ephemeral-data-model.md)—how the connector handles data without persistence * [OID4VP protocol](/eudiw-connector/explanations/standards/oid4vp-protocol.md)—the verification protocol mandated by eIDAS 2.0 --- ### High Assurance Interoperability Profile (HAIP) When multiple wallet providers, attestation providers, and Relying Parties implement the same protocol, small differences in how they interpret optional features can break interoperability. The High Assurance Interoperability Profile (HAIP) solves this by narrowing the choices available in the OpenID for Verifiable Presentations (OID4VP) and OpenID for Verifiable Credential Issuance (OID4VCI) protocols to a single, well-defined path that all participants follow. The specific version referenced by the Architecture Reference Framework (ARF) is OpenID4VC High Assurance Interoperability Profile 1.0. #### Why HAIP matters[​](#why-haip-matters "Direct link to Why HAIP matters") OID4VP and OID4VCI are flexible protocols with many optional parameters, credential formats, and transport mechanisms. This flexibility is useful for experimentation, but it creates a problem for production deployments: two implementations that both "support OID4VP" might not work together if they made different choices about which options to use. HAIP eliminates this ambiguity. By specifying exactly which credential formats, proof mechanisms, and transport options to use, HAIP ensures that any compliant wallet can interact with any compliant Relying Party or credential issuer without negotiation or fallback logic. #### What HAIP constrains[​](#what-haip-constrains "Direct link to What HAIP constrains") HAIP defines requirements across both credential verification and credential issuance. ##### Verification (OID4VP)[​](#verification-oid4vp "Direct link to Verification (OID4VP)") * **Credential format**—HAIP mandates SD-JWT VC with key binding as the credential format for remote presentations. Every credential presentation must include cryptographic proof that the presenter holds the credential's private key. This ensures that credentials cannot be replayed by unauthorized parties. * **Query language**—HAIP mandates Digital Credentials Query Language (DCQL) as the query language for specifying which credentials and claims a Relying Party needs. This replaces older query mechanisms with a single standardized approach. * **Request transport**—HAIP requires signed request objects, which the wallet verifies before responding. Request objects may also be optionally encrypted for additional confidentiality. The wallet authenticates the Relying Party and confirms the integrity of the request before disclosing any credentials. * **Response transport**—HAIP mandates a response mode that ensures encrypted delivery of credentials back to the Relying Party. The wallet encrypts the presentation response so that only the requesting Relying Party can read it, protecting credential data in transit. HAIP also profiles the presentation of ISO/IEC 18013-5-compliant (mDoc) attestations over OID4VP for remote flows, in addition to SD-JWT VC. The connector currently focuses on SD-JWT VC presentations. ##### Issuance (OID4VCI)[​](#issuance-oid4vci "Direct link to Issuance (OID4VCI)") * **Credential format**—HAIP requires support for at least one of SD-JWT VC or mDoc as the credential format for issuance. The connector implements SD-JWT VC, the same format used for verification. This ensures credentials are issued in a format that any HAIP-compliant Relying Party can verify. * **Token binding**—HAIP requires DPoP (Demonstrating Proof-of-Possession) to bind access tokens to the wallet's key pair. This prevents token theft and replay attacks during the issuance exchange. * **Key resolution**—HAIP mandates X.509 certificate chains for issuer key resolution, allowing wallets to verify the issuer's identity through a trust chain rather than pre-shared keys. * **Cryptographic holder binding**—every issued credential must bind to the wallet's key pair, ensuring only the legitimate holder can present the credential later. #### How the connector implements HAIP[​](#how-the-connector-implements-haip "Direct link to How the connector implements HAIP") The Truvity EUDIW Connector implements the HAIP profile by default for both verification and issuance flows. When you create a presentation request or a credential offer, the connector automatically applies HAIP-compliant settings. This means you don't need to manually configure protocol options or worry about compatibility with different wallet implementations. For verification, the connector handles: * Generating signed authorization requests that wallets can verify. * Accepting SD-JWT VC credential presentations with key binding proof. * Validating credential integrity and proof of possession. * Delivering results through the encrypted response mechanism defined by the profile. For issuance, the connector handles: * Issuing credentials in SD-JWT VC format with cryptographic holder binding. * Enforcing DPoP token binding throughout the issuance exchange. * Resolving issuer identity through X.509 certificate chains. #### HAIP and the EUDI Wallet ecosystem[​](#haip-and-the-eudi-wallet-ecosystem "Direct link to HAIP and the EUDI Wallet ecosystem") The European Digital Identity Wallet ecosystem relies on HAIP as the baseline interoperability profile. Member state wallet implementations, certified Relying Parties, and credential issuers are expected to support HAIP, making it the common language for cross-border credential exchange. By building on HAIP, the connector ensures compatibility with wallets from different member states and different wallet providers, without requiring you to handle protocol-level differences in your integration. #### Further reading[​](#further-reading "Direct link to Further reading") * [OID4VP protocol](/eudiw-connector/explanations/standards/oid4vp-protocol.md)—how the underlying verification protocol works * [OID4VCI protocol](/eudiw-connector/explanations/standards/oid4vci-protocol.md)—how the underlying issuance protocol works * [SD-JWT VC credential format](/eudiw-connector/explanations/credential-formats/sd-jwt.md)—the credential format required by HAIP * [Digital Credentials Query Language (DCQL)](/eudiw-connector/explanations/standards/dcql.md)—the query language HAIP mandates for credential requests --- ### OID4VCI protocol When a bank needs to issue a credential to a customer's EUDI Wallet—for example, an Account Ownership Credential after opening an account—both systems need a standard way to exchange that credential securely. **OpenID for Verifiable Credential Issuance (OID4VCI)** is that standard. It defines how credential issuers create offers, how wallets discover what an issuer supports, and how wallets request and receive credentials. The Truvity EUDIW Connector implements OID4VCI as the core protocol for all credential issuance flows. Where [OID4VP](/eudiw-connector/explanations/standards/oid4vp-protocol.md) handles the presentation side (wallet to Relying Party), OID4VCI handles the issuance side (issuer to wallet). Together, they form the two complementary credential exchange protocols in the EUDI ecosystem. #### Why OID4VCI matters[​](#why-oid4vci-matters "Direct link to Why OID4VCI matters") Before OID4VCI, there was no standard way for issuers and digital wallets to exchange credentials. Each implementation used proprietary protocols, making cross-border and cross-vendor interoperability impossible. OID4VCI defines the message structures, transaction flows, and interface specification for credential issuance, building on OAuth 2.0. Because every EUDI Wallet and every credential issuer implements the same protocol, a credential issued by one organization can be received by any compliant wallet in any member state. Key benefits: * **Standardized issuance across the EUDI ecosystem.** Any compliant issuer can deliver credentials to any compliant wallet, regardless of vendor or member state. * **Built on OAuth 2.0.** OID4VCI extends familiar OAuth 2.0 grant types, so the token exchange and authorization patterns are well-understood and widely supported. * **Interoperability by design.** Wallets don't need custom integrations for each issuer. A single protocol implementation handles all credential types. #### Protocol flow[​](#protocol-flow "Direct link to Protocol flow") The OID4VCI flow begins when the issuer creates a credential offer and ends when the wallet receives a signed credential. The flow is asynchronous from the issuer's perspective: the issuer creates the offer, and the connector delivers a callback when the wallet completes (or fails) the exchange. ##### Conceptual steps[​](#conceptual-steps "Direct link to Conceptual steps") 1. **The issuer creates a credential offer.** The issuer's backend tells the connector what credential to issue and provides the claims. The connector returns a credential offer URI that the issuer displays to the user as a QR code or deep link. 2. **The wallet discovers issuer metadata.** The wallet retrieves two metadata documents: one describing the issuer's capabilities (supported credential types, signing algorithms, proof requirements) and one describing the authorization server (token endpoint, supported grant types). This discovery step lets the wallet configure itself automatically for any issuer. 3. **The wallet exchanges the pre-authorized code for an access token.** The wallet presents the pre-authorized code from the offer to the authorization server's token endpoint. The wallet includes a [DPoP](/eudiw-connector/explanations/privacy-security/dpop.md) proof to bind the resulting access token to its key, preventing token theft. 4. **The wallet requests a nonce.** The wallet obtains a single-use nonce from the connector. This nonce prevents replay attacks during the credential request. 5. **The wallet creates a key proof.** The wallet generates a cryptographic proof demonstrating possession of the key that the credential binds to. The proof includes the nonce from the previous step. 6. **The wallet requests the credential.** The wallet sends the key proof and its DPoP-bound access token to the connector's credential endpoint. 7. **The connector signs and returns the credential.** The connector validates the proofs, signs the credential using the issuer's signing certificate, and returns it to the wallet. The credential is cryptographically bound to the wallet's key, so only the wallet holder can present it later. 8. **The connector delivers a callback to the issuer backend.** The connector notifies the issuer's backend whether issuance succeeded, failed, or expired. The issuer uses this callback to update its own records (for example, marking an account as fully set up). #### Pre-authorized code flow[​](#pre-authorized-code-flow "Direct link to Pre-authorized code flow") OID4VCI supports multiple grant types, but the connector uses the **pre-authorized code flow**. In this flow, the issuer has already authenticated the user and decided to issue a credential—the wallet doesn't need to authenticate the user again at an authorization server. This is the natural fit for scenarios where issuance happens as part of an existing business process. For example, after a bank completes identity verification during account opening, it already knows who the customer is. The pre-authorized code flow lets the bank issue a credential directly, without requiring the customer to log in again through a separate authorization step. The pre-authorized code flow extends OAuth 2.0 with a dedicated grant type. The authorization server issues a pre-authorized code when the issuer creates the offer, and the wallet exchanges that code for an access token at the token endpoint—the same token endpoint pattern used in standard OAuth 2.0 flows. #### Metadata discovery[​](#metadata-discovery "Direct link to Metadata discovery") Before a wallet can request a credential, it needs to know what the issuer supports and where to exchange tokens. OID4VCI solves this with two metadata documents that the wallet retrieves automatically. **Credential issuer metadata** describes the issuer's capabilities: which credential types are available, what formats they use, which signing algorithms are supported, and what proof types the wallet must provide. This document lets the wallet determine whether it can handle the offered credential type before starting the exchange. **Authorization server metadata** describes the token endpoint and the grant types it supports. The wallet uses this to locate the token endpoint where it exchanges the pre-authorized code for an access token. Together, these two metadata documents make the protocol self-describing. A wallet encountering a new issuer for the first time can configure itself automatically by reading the metadata, without any prior knowledge of that specific issuer's setup. #### Relationship to OID4VP[​](#relationship-to-oid4vp "Direct link to Relationship to OID4VP") OID4VCI and [OID4VP](/eudiw-connector/explanations/standards/oid4vp-protocol.md) are complementary protocols that cover the two directions of credential exchange in the EUDI ecosystem: * **OID4VCI** moves credentials from issuer to wallet. The issuer creates an offer, and the wallet receives a signed credential. * **OID4VP** moves credentials from wallet to Relying Party. The Relying Party creates a presentation request, and the wallet shares selected attributes from a credential. The same wallet, the same credential formats, and the same trust infrastructure underpin both protocols. A credential issued via OID4VCI can be presented via OID4VP to any Relying Party that trusts the issuer. This symmetry is what makes the EUDI ecosystem work—issuance and presentation are standardized independently, so any issuer-wallet-verifier combination is interoperable. #### Specification references[​](#specification-references "Direct link to Specification references") * [OpenID for Verifiable Credential Issuance (OID4VCI)](https://openid.net/specs/openid-4-verifiable-credential-issuance-1_0.html)—the core protocol specification * [RFC 9449 (DPoP)](https://datatracker.ietf.org/doc/html/rfc9449)—Demonstration of Proof-of-Possession for sender-constrained tokens * [RFC 6749 (OAuth 2.0)](https://datatracker.ietf.org/doc/html/rfc6749)—the authorization framework that OID4VCI extends #### Further reading[​](#further-reading "Direct link to Further reading") * [DPoP and sender-constrained tokens](/eudiw-connector/explanations/privacy-security/dpop.md)—how DPoP secures token exchanges during issuance * [OID4VP protocol](/eudiw-connector/explanations/standards/oid4vp-protocol.md)—the complementary protocol for credential presentation * [Connector architecture](/eudiw-connector/explanations/architecture/connector-architecture.md)—how the connector implements both issuance and verification protocols --- ### OID4VP protocol When a bank needs to verify a customer's identity using their EUDI Wallet, both systems need to speak the same language. **OpenID for Verifiable Presentations (OID4VP)** is that language. It defines how Relying Parties request credentials from wallets and how wallets deliver verified responses back. The Truvity EUDIW Connector implements OID4VP as the core protocol for all credential verification flows. #### Why OID4VP matters[​](#why-oid4vp-matters "Direct link to Why OID4VP matters") Before OID4VP, there was no standard way for digital wallets and verification systems to exchange credentials. Each implementation used proprietary protocols, making cross-border and cross-vendor interoperability impossible. OID4VP defines message structures, transaction flows, and an interface specification for credential presentation, building on concepts from OAuth 2.0. Because every EUDI Wallet and every Relying Party implements the same protocol, a wallet issued in one member state works with a Relying Party in any other member state. note The EUDI ecosystem also supports proximity presentation flows using ISO/IEC 18013-5 for scenarios where the user and the Relying Party are physically co-located. OID4VP covers remote flows only. #### Request delivery through the Digital Credentials API[​](#request-delivery-through-the-digital-credentials-api "Direct link to Request delivery through the Digital Credentials API") In the EUDI ecosystem, OID4VP presentation requests don't travel directly from the Relying Party to the wallet. Instead, the W3C Digital Credentials API (for browser-based flows) or the platform API (for app-based flows) mediates the interaction. The browser and operating system handle wallet selection, origin verification, and session binding on behalf of the user. This architecture means the Relying Party never needs to know which wallet the user has installed. The browser and OS route the request to the appropriate wallet and ensure the response comes back through a secure, authenticated channel. #### Protocol flow[​](#protocol-flow "Direct link to Protocol flow") The OID4VP flow is asynchronous. Your app starts a verification session, the user responds through their wallet, and the connector delivers the result to your system through a callback. ##### Request creation[​](#request-creation "Direct link to Request creation") When your app creates a presentation request, the connector builds a signed authorization request. This request specifies: * The credentials and attributes you need, expressed as a [DCQL query](/eudiw-connector/explanations/standards/dcql.md) * A cryptographic nonce that uniquely identifies this session * Optional transactional data that binds the presentation to a specific action (for example, a payment authorization) The connector signs the request using your X.509 certificate, which allows the wallet to verify your identity as a registered Relying Party. ##### Request delivery[​](#request-delivery "Direct link to Request delivery") How the request reaches the user's wallet depends on the scenario: * **Same-device flow**: The connector provides an `openid4vp://` deep link URI. The browser or platform API (such as the W3C Digital Credentials API) forwards the request to the wallet. The operating system handles wallet selection if the device hosts multiple wallets. This applies when both your app and the wallet run on the same device. * **Cross-device flow**: The connector provides an `openid4vp://` URI that your app renders as a QR code. The user scans the QR code with their phone. In the EUDI ecosystem, the browser may initiate a secure tunnel using the FIDO CTAP 2.2 hybrid flow, where the device emits a BLE advertisement as a proximity check to mitigate relay attacks. After the tunnel is established, the OID4VP request is sent through it. This is the typical scenario when the user is on a desktop and their wallet is on their phone. In both cases, the wallet validates the signed request before proceeding. ##### Trust verification[​](#trust-verification "Direct link to Trust verification") Before showing the request to the user, the wallet authenticates your Relying Party. It validates your X.509 certificate chain against the [trusted list](/eudiw-connector/explanations/trust-revocation/trust-lists.md) of the relevant jurisdiction. If the certificate is invalid or revoked, the wallet blocks the request. This mechanism protects users from presenting credentials to unauthorized parties. ##### User consent and selective disclosure[​](#user-consent-and-selective-disclosure "Direct link to User consent and selective disclosure") The wallet displays who is requesting data and what data is requested. The user must explicitly consent before any data leaves the wallet. Wallets enforce [selective disclosure](/eudiw-connector/explanations/privacy-security/selective-disclosure.md). If you only need to verify a user's age, you can request just the `age_over_18` attribute (if defined in the attestation scheme) rather than the full date of birth. The wallet shares only the specific attributes you request and withholds everything else. ##### Response submission[​](#response-submission "Direct link to Response submission") After the user consents, the wallet constructs a verifiable presentation containing: * The disclosed attributes approved by the user * A [key binding](/eudiw-connector/explanations/privacy-security/key-binding.md) proof that demonstrates legitimate possession of the credential * The original issuer signatures on the credential The wallet encrypts this response using an ephemeral public key from the authorization request and submits it to the connector. Response encryption is mandated by the [HAIP profile](/eudiw-connector/explanations/standards/haip.md), which constrains OID4VP for the EUDI ecosystem. ##### Verification[​](#verification "Direct link to Verification") The connector decrypts the response and validates it: * Checks the credential structure and format * Verifies the issuer's signature and trust chain * Confirms key binding (proof of possession) * Checks revocation status * Validates that any transactional data was correctly signed ##### Result delivery[​](#result-delivery "Direct link to Result delivery") After verification, the connector delivers the result to your app through a callback. The connector uses an [ephemeral data model](/eudiw-connector/explanations/privacy-security/ephemeral-data-model.md)—it processes credentials in memory and does not persist user data. You receive the verified attributes in a Presented Credentials Event and must capture them immediately. For details on the event statuses your callback can receive, see the [callback events reference](/eudiw-connector/reference/callback-events.md). #### Security mechanisms[​](#security-mechanisms "Direct link to Security mechanisms") ##### Nonce[​](#nonce "Direct link to Nonce") Every presentation request includes a unique nonce. The wallet signs this nonce as part of its response, which serves two purposes: * **Replay prevention**: A captured response can't be reused because the nonce is single-use * **Session binding**: The nonce ties the wallet's response to the specific request that initiated it ##### Ephemeral encryption[​](#ephemeral-encryption "Direct link to Ephemeral encryption") Each session uses a unique encryption key pair. The connector includes the public key in the authorization request, and the wallet encrypts its response with it. This ensures that even if an attacker intercepts network traffic, the credential data remains confidential. The connector deletes the encryption keys after the session completes. ##### Transactional data[​](#transactional-data "Direct link to Transactional data") For high-value operations, you can include transactional data in the presentation request. The wallet displays this data to the user and signs over it, creating a cryptographic binding between the user's consent and the specific action. This prevents a presentation intended for one transaction from being replayed in a different context. #### Specification version[​](#specification-version "Direct link to Specification version") The EUDI ecosystem references OpenID for Verifiable Presentations 1.0 as identified in the ARF's Set of Technical Specifications. #### Further reading[​](#further-reading "Direct link to Further reading") * [HAIP profile](/eudiw-connector/explanations/standards/haip.md)—the security profile that constrains OID4VP for the EUDI ecosystem * [DCQL query language](/eudiw-connector/explanations/standards/dcql.md)—how to specify which credentials and attributes to request * [Connector architecture](/eudiw-connector/explanations/architecture/connector-architecture.md)—how the connector implements the protocol --- ### Certificates in EUDI In the EUDI Wallet ecosystem, trust is bidirectional. While the Relying Party (RP) verifies the user's credentials, the EUDI Wallet must also verify the RP's identity before presenting sensitive personal data. This verification relies on certificates issued as part of the RP registration process. #### Certificate types[​](#certificate-types "Direct link to Certificate types") The EUDI ecosystem defines two certificate types for Relying Parties. These are fundamentally different technical artifacts despite both being called "certificates." ##### Access certificates[​](#access-certificates "Direct link to Access certificates") An access certificate is an X.509 certificate that binds your organization's identity to a public key. EUDI Wallets use this certificate to verify who is requesting data and to confirm that the request has not been tampered with. When the Truvity EUDIW Connector creates an authorization request, it signs the request using the [signing identity key](/eudiw-connector/explanations/privacy-security/encryption-key-management.md)—the private key associated with your access certificate. The wallet validates the signature, checks the certificate chain against trusted roots, and verifies that the certificate has not been revoked. Only after these checks pass does the wallet show the consent screen to the user. Access certificates identify the entity but do not indicate the entity type (Relying Party, PID Provider, or attestation provider) or the attestation types the entity has registered to issue or request. That information is provided by registration certificates or the Registrar's online service. Access certificates may be logged in Certificate Transparency logs per CIR 2025/848, enabling detection of erroneously or fraudulently issued certificates. ##### Registration certificates[​](#registration-certificates "Direct link to Registration certificates") A registration certificate is a signed data object, formatted as a JWT or CWT, that describes your organization's registered intended uses and indicates which attributes you have registered to intend to request from users. Unlike access certificates, registration certificates are not X.509 certificates. note Registration certificates are optional. Whether they are issued depends on Member State policy. When registration certificates are not available, the wallet retrieves the same information from the Registrar's online service using the Registrar URL and Relying Party identifier from the presentation request. #### How the connector uses certificates[​](#how-the-connector-uses-certificates "Direct link to How the connector uses certificates") The connector uses your access certificate in the [OID4VP protocol](/eudiw-connector/explanations/standards/oid4vp-protocol.md) flow. When you create a presentation request, the connector signs the authorization request using the private key associated with your access certificate. The signed request includes your certificate chain, allowing the wallet to: 1. Verify the signature to confirm the request has not been altered. 2. Validate the certificate chain from your certificate up to a trusted root recognized by the wallet. 3. Check that the certificate has not been revoked. If any check fails, the wallet rejects the request. For details on wallet-facing error responses, see [Error codes](/eudiw-connector/reference/error-codes.md). #### Your responsibilities[​](#your-responsibilities "Direct link to Your responsibilities") You are responsible for obtaining and managing your own certificates: * **Obtain certificates**: Get your X.509 access certificate from an Access Certificate Authority associated with the Registrar in your member state. * **Configure the connector**: Provide your certificate and the associated private key to the connector at deployment time. * **Monitor expiration**: Track certificate validity and handle renewals before expiration. * **Handle revocation**: If a private key is compromised, revoke the certificate and deploy a new one. Wallets check revocation status and reject requests signed with revoked certificates. ##### Sandbox and development[​](#sandbox-and-development "Direct link to Sandbox and development") For development and testing, you can generate self-signed certificates to use with the connector. These allow you to test the full verification flow without obtaining a production certificate. Production EUDI Wallets reject self-signed certificates because they do not chain to a trusted root. Use development-enabled wallets or test harnesses for integration testing. #### Trust anchors[​](#trust-anchors "Direct link to Trust anchors") The ARF defines a trust anchor as a combination of a public key and the identifier of the associated entity. For a certificate to be accepted by a production EUDI Wallet, it must chain up to a trust anchor published in a [List of Trusted Entities (LoTE)](/eudiw-connector/explanations/trust-revocation/trust-lists.md). Access Certificate Authority trust anchors are published in LoTEs, and wallets use these to verify the certificate chains of access certificates presented by Relying Parties. #### Revocation[​](#revocation "Direct link to Revocation") Certificates can be revoked before they expire (for example, if a private key is compromised). Wallets check revocation status using mechanisms defined in the certificate. If your certificate is revoked, wallets stop accepting presentation requests signed with that certificate until you deploy a new valid one. The connector also checks revocation status for the X.509 certificates used by credential issuers to sign credentials. When a credential's issuer signs it with an X.509 certificate chain, the connector can verify that no certificate in that chain has been revoked via a Certificate Revocation List (CRL). This is an optional feature, off by default. See [Revocation mechanisms](/eudiw-connector/explanations/trust-revocation/revocation-mechanisms.md) for how CRL checking works, and [Configure X.509 trust anchor verification](/eudiw-connector/how-to-guides/configure-trust-anchors.md) to enable it. #### Further reading[​](#further-reading "Direct link to Further reading") * [Manage certificates](/eudiw-connector/how-to-guides/certificates.md)—how to generate self-signed certificates for development and configure production certificates in the connector * [Encryption and key management](/eudiw-connector/explanations/privacy-security/encryption-key-management.md)—how the connector manages signing and encryption keys, including the signing identity key used with access certificates * [OID4VP protocol](/eudiw-connector/explanations/standards/oid4vp-protocol.md)—the protocol that uses signed authorization requests to verify credentials between wallets and Relying Parties * [Trust establishment](/eudiw-connector/explanations/trust-revocation/trust-establishment.md)—how wallets, attestation providers, and Relying Parties establish mutual trust using government authorities as trust anchors * [Trust lists](/eudiw-connector/explanations/trust-revocation/trust-lists.md)—how Trusted Lists and Lists of Trusted Entities publish the trust anchors that wallets use to validate certificate chains --- ### LoTL trust verification When your app receives a credential through the Truvity EUDIW Connector, you need to know whether the issuer is recognized by the EU trust framework—and what category of credential the issuer is authorized to produce. The connector resolves this automatically by verifying the credential's issuer certificate chain against the EU List of Trusted Lists (LoTL) hierarchy, determining whether the issuer holds a valid entry on the appropriate trust list for the credential category it claims to issue. This page explains how LoTL trust verification works at the conceptual level—the credential categories, verification paths, trust failure reasons, and staleness signals. For configuration steps, see [Configure trust anchor verification](/eudiw-connector/how-to-guides/configure-trust-anchors.md). For the callback payload field reference, see [Callback events](/eudiw-connector/reference/callback-events.md). #### Credential categories[​](#credential-categories "Direct link to Credential categories") The EU trust framework classifies credentials into four categories based on the legal status and governance model of the issuer. The connector determines the credential category from the issuer's trust list entry and reports it on the callback payload as the `credentialCategory` field. See [Callback events](/eudiw-connector/reference/callback-events.md) for the field reference. * **PID (Personal Identification Data)**—Government-issued digital identity credentials. Issued by PID Providers authorized by their member state. Trust anchors published in the PID Provider LoTE. * **QEAA (Qualified Electronic Attestation of Attributes)**—Credentials from qualified trust service providers operating under eIDAS 2.0 Article 22. Trust anchors published in the member state's national Trusted List. * **PuB-EAA (Published under a specific legal basis)**—Credentials from providers operating under a legal basis other than the QTSP framework. The provider signs credentials using a qualified certificate issued by a QTSP. Trust anchors published in the member state's national Trusted List with a conformity assessment reference. * **Non-qualified EAA**—Credentials from providers operating under domain-specific Attestation Rulebooks. Trust anchors may appear on voluntary entries in national Trusted Lists; when absent, the connector falls back to statically configured trust anchors. #### Verification paths[​](#verification-paths "Direct link to Verification paths") Each credential category resolves trust through a different path in the LoTL hierarchy: * **PID**: Issuer certificate chain → PID Provider LoTE (JSON, ETSI TS 119 602) → LoTL * **QEAA**: Issuer certificate chain → National Trusted List (XML, ETSI TS 119 612) → LoTL * **PuB-EAA**: Issuer certificate chain (which includes a QTSP-issued qualified certificate) → National Trusted List (PuB-EAA Provider entry) → LoTL * **Non-qualified EAA**: Issuer certificate chain → Voluntary national Trusted List entry → LoTL; if no entry found, fallback to statically configured trust anchors The EU Commission publishes the List of Trusted Lists (LoTL), which points to each Member State's national Trusted List and Lists of Trusted Entities. When the connector receives a credential with an X.509 certificate chain, it resolves the issuer's certificate against the appropriate list based on the credential category: * PIDs resolve against the PID Provider LoTE * QEAAs and PuB-EAAs resolve against the national Trusted List. For PuB-EAAs, the certificate chain includes a QTSP-issued qualified certificate as an intermediate—the connector verifies the full chain up to the PuB-EAA Provider's trust anchor published on the Trusted List (service type `EAA/Pub-EAA`), not against the QTSP's own entry. * Non-qualified EAAs attempt the national Trusted List first, then fall back to statically configured trust anchors #### Trust resolution modes[​](#trust-resolution-modes "Direct link to Trust resolution modes") The connector supports two modes for resolving issuer trust. The mode is set at the connector instance level. The active mode is reported indirectly through the presence or absence of enriched trust fields on the callback payload. * **LoTL-enabled mode (production path)**—The connector fetches and verifies the EU LoTL hierarchy, builds a trust store, and resolves issuer trust dynamically. This is the production configuration for deployments that need to verify credentials from any EU-recognized issuer. * **Static-only mode (fallback)**—The connector resolves trust only against manually configured trust anchor certificates. This mode is for environments without LoTL infrastructure (early testing, isolated sandboxes, or pre-production deployments where the issuer set is known and fixed). LoTL-enabled mode is the recommended production configuration. Static-only mode remains available as a fallback—see [Configure trust anchor verification](/eudiw-connector/how-to-guides/configure-trust-anchors.md) for setup. #### Trust verification policy[​](#trust-verification-policy "Direct link to Trust verification policy") The connector can be configured to either report trust outcomes as informational fields or enforce them as a verification precondition. This is configured per credential category: * **evaluate (default)**—Trust outcomes are reported as fields on successful callback payloads. The flow completes regardless of the trust verdict. Your backend decides what to do with the result. * **enforce**—Trust failure for the configured category causes the flow to fail with a non-success callback status. The credential is never delivered to your backend. - **disabled**—Trust fields are omitted entirely from the callback for the configured category. The default is `evaluate` for all credential categories—trust outcomes are informational, and your backend applies the appropriate legal weight to each verification result. For configuration, see [Configure trust anchor verification](/eudiw-connector/how-to-guides/configure-trust-anchors.md). #### Trust failure reasons[​](#trust-failure-reasons "Direct link to Trust failure reasons") When the connector cannot resolve an issuer against the LoTL hierarchy, it reports a trust failure reason on the callback payload. This appears as the `trustFailureReason` field when `isTrusted` is `false`. See [Callback events](/eudiw-connector/reference/callback-events.md) for the field reference. Four reasons are possible: * **`issuer_not_found`**—The issuer's certificate does not match any entry on any trust list in the LoTL hierarchy. The issuer may not be registered, may be using a certificate not yet published, or may be operating outside the EU trust framework. * **`issuer_withdrawn`**—The issuer was found on a trust list, but the entry's status is "withdrawn" or "revoked." The member state's supervisory body has terminated the issuer's authorization. * **`issuer_suspended`**—The issuer was found on a trust list, but the entry's status is "suspended." The member state's supervisory body has temporarily suspended the issuer's authorization pending review. * **`trust_list_unavailable`**—The trust list that should contain the issuer's entry could not be fetched and no valid cached copy is available within the staleness window. The connector cannot determine the issuer's trust status. #### Staleness signals[​](#staleness-signals "Direct link to Staleness signals") Trust list data has a limited freshness window. The connector periodically refreshes its trust data from the LoTL hierarchy. When a refresh fails, the connector may use cached trust data to avoid blocking verifications entirely. The staleness signal tells your backend whether the verification used fresh or stale trust data—this appears as the `staleTrustData` field on the callback payload. See [Callback events](/eudiw-connector/reference/callback-events.md) for the field reference. Two conditions are reported: * **`cachedFallback`**—The connector used cached trust data because a fresh fetch from the trust list source failed. The data was still within the configured staleness window. * **`pastNextUpdate`**—The cached trust data is past the publisher's declared next update timestamp. The data may be outdated. Both flags help your backend make informed decisions. For example, you might accept a verification with `cachedFallback` but flag it for re-verification later, while `pastNextUpdate` might warrant additional scrutiny. When trust data is fresh, the `staleTrustData` field is absent from the callback. #### Applicability[​](#applicability "Direct link to Applicability") Trust verification applies only to credentials that include an X.509 certificate chain (`x5c` header). In HAIP-compliant ecosystems, SD-JWT VC credentials always include an `x5c` chain for issuer key resolution. Credentials without a certificate chain (for example, credentials using a DID-based issuer key) are not subject to trust anchor verification. #### Further reading[​](#further-reading "Direct link to Further reading") * [Trust lists](/eudiw-connector/explanations/trust-revocation/trust-lists.md)—background on the EU trust list infrastructure * [Trust establishment](/eudiw-connector/explanations/trust-revocation/trust-establishment.md)—the overall trust model in the EUDI ecosystem * [Configure trust anchor verification](/eudiw-connector/how-to-guides/configure-trust-anchors.md)—set up LoTL-driven trust verification * [Callback events](/eudiw-connector/reference/callback-events.md)—full callback payload field reference * [Revocation mechanisms](/eudiw-connector/explanations/trust-revocation/revocation-mechanisms.md)—how credential and certificate revocation checking works --- ### Revocation mechanisms Credentials can be revoked by their issuers at any time. A user might lose their device, a document might expire, or eligibility might change. As a Relying Party, you need assurance that a presented credential is still valid at the moment of verification. The Truvity EUDIW Connector checks credential-level revocation automatically during every verification flow. It determines whether the credential itself has been revoked by its issuer using the Status List mechanism described below. A second layer, certificate-level revocation, verifies that the X.509 certificate used to sign the credential has not been revoked by its Certificate Authority. This layer is optional and off by default. #### The Status List mechanism[​](#the-status-list-mechanism "Direct link to The Status List mechanism") The EUDI ecosystem uses the IETF Token Status List specification (draft-ietf-oauth-status-list) to manage revocation in a privacy-preserving way. Rather than querying the issuer about a specific credential (which would reveal the holder's activity to the issuer), the connector fetches a published Status List that contains the status of many credentials at once. A Status List is a bitstring in which each bit or group of bits denotes the current revocation or suspension status of one attestation. Each credential is assigned an index in the list at issuance. During verification, the connector checks the value at that index to determine whether the credential has been revoked. This approach ensures unlinkability. The issuer publishes the list without knowing which specific credential a Relying Party is checking. note Attestations with a validity period of less than 24 hours may not include revocation information. The ARF does not require revocation data for short-lived attestations because their brief validity period inherently limits the window of exposure. #### Automatic verification[​](#automatic-verification "Direct link to Automatic verification") You do not need to fetch or parse Status Lists yourself. The connector handles this automatically when it receives a presentation: 1. **Extracts status information** from the presented credential 2. **Fetches the latest Status List** from the issuer's published endpoint 3. **Checks the credential's status** at its assigned index If the credential has been revoked, the connector reports this in the [Presented Credentials Event](/eudiw-connector/reference/callback-events.md) delivered to your callback. The per-credential `isRevoked` field is set to `true`, allowing your app to decide how to handle the revoked credential. #### Handling revocation in your integration[​](#handling-revocation-in-your-integration "Direct link to Handling revocation in your integration") The connector reports revocation status as per-credential fields within the [Presented Credentials Event](/eudiw-connector/reference/callback-events.md), not as an overall flow failure. When a revoked credential is presented: * The event status is `FULFILLED` (the presentation flow completed successfully) * Each credential in the `credentials` map includes `supportRevocation` and `isRevoked` fields * If `supportRevocation` is `true` and `isRevoked` is `true`, the credential's issuer has revoked it * Your system must check the `isRevoked` field for each credential and decide whether to accept or reject the transaction Revocation does not trigger `VERIFICATION_FAILED`. That status is reserved for cryptographic failures (invalid signatures, Key Binding JWT validation errors), DCQL mismatches, and transaction data hash failures—cases where the presentation itself is technically invalid. A revoked credential is a valid presentation of a credential that happens to be revoked, so the connector delivers the full credential data and lets your app decide what to do. This design gives you full control over the revocation policy. The connector provides the revocation data; your app decides how to act on it. #### PID and Wallet Unit revocation[​](#pid-and-wallet-unit-revocation "Direct link to PID and Wallet Unit revocation") When you verify that a PID is not revoked, you also gain assurance that the underlying Wallet Unit is still valid. The ARF requires PID Providers to regularly check whether the Wallet Unit has been revoked, and to revoke the PID if it has. This means there is no need for a separate mechanism to verify Wallet Unit revocation directly with the Wallet Provider. PID revocation checking implicitly covers Wallet Unit revocation. #### Certificate Revocation List (CRL) checking[​](#certificate-revocation-list-crl-checking "Direct link to Certificate Revocation List (CRL) checking") In addition to credential-level revocation (Status List), the connector can also check whether the X.509 certificates used to sign credentials have been revoked by their issuing Certificate Authority. In HAIP-compliant ecosystems, SD-JWT VC credentials include an `x5c` certificate chain in the JWT header—this is mandatory per the HAIP profile for issuer key resolution. CRL checking verifies that none of the certificates in that chain have been revoked. CRL checking is not mandated by the ARF, OID4VP, SD-JWT VC, or HAIP specifications—it is a standard X.509 PKI security practice (RFC 5280) that some EUDI federation deployments require. The connector implements it as an optional, configurable feature that is off by default. ##### How it works[​](#how-it-works "Direct link to How it works") When a credential includes an `x5c` header (which is always the case for SD-JWT VCs in HAIP-compliant ecosystems), the connector performs up to two verification steps: 1. **Chain-internal validation**—always runs when `x5c` is present, regardless of configuration. The connector verifies that each certificate in the chain is properly signed by the next, that all certificates are within their validity periods, and that Basic Constraints and Key Usage extensions are correct. This is standard X.509 path validation per RFC 5280. If this fails, the credential fails verification. Credentials without an `x5c` header (non-HAIP credential formats) are unaffected. 2. **Trust anchor resolution and CRL checking**—runs only when enabled via configuration. The connector resolves the chain's last certificate against a set of configured trust anchors. It first attempts Authority Key Identifier (AKI) to Subject Key Identifier (SKI) matching per RFC 5280. If no match is found via AKI/SKI, it falls back to Issuer Distinguished Name matching combined with signature verification. Once a trust anchor is matched, the connector verifies the last certificate's signature against it, then fetches the Certificate Revocation List from each certificate's CRL Distribution Point extension, verifies the CRL's signature and freshness, and checks whether the certificate's serial number appears in the revocation list. If no valid CRL can be obtained from any distribution point, the certificate is treated as not revoked. ##### Callback fields[​](#callback-fields "Direct link to Callback fields") When a credential includes an `x5c` certificate chain, the callback payload's per-credential object includes: * `supportTrustAnchor`—set to `true` when the credential was signed with an `x5c` header * `isTrusted`—whether the chain terminated at a configured trust anchor and the last certificate's signature was verified against it. `false` when trust anchor verification is off or no matching trust anchor is found. Only present when `supportTrustAnchor` is `true`. * `isCertificateRevoked`—whether any certificate in the chain was found on a CRL. `false` when trust anchor verification is off (CRL checking is skipped) or when no valid CRL could be obtained. Only present when `supportTrustAnchor` is `true`. See [Callback events](/eudiw-connector/reference/callback-events.md) for the full credential object field reference. note CRL checking is off by default and requires configuration. See [Configure X.509 trust anchor verification](/eudiw-connector/how-to-guides/configure-trust-anchors.md) for setup steps. #### Further reading[​](#further-reading "Direct link to Further reading") * [Trust establishment](/eudiw-connector/explanations/trust-revocation/trust-establishment.md)—the overall trust model that includes revocation * [Callback events](/eudiw-connector/reference/callback-events.md)—Presented Credentials Event statuses including VERIFICATION\_FAILED * [Connector architecture](/eudiw-connector/explanations/architecture/connector-architecture.md)—how the connector processes presentations * [Configure X.509 trust anchor verification](/eudiw-connector/how-to-guides/configure-trust-anchors.md)—enable trust anchor resolution and CRL checking --- ### Trust establishment In the EUDI Wallet ecosystem, multiple parties must trust each other without prior relationships. A bank in Germany needs to trust a PID issued in Portugal. A wallet in France needs to verify that a Relying Party in Spain is legitimate. Trust establishment defines how this works using government authorities as trust anchors and X.509 certificates as the primary verification mechanism. For PIDs, QEAAs, PuB-EAAs, and access certificates, interoperability is achieved through a PKI following X.509 certificate standards. Non-qualified EAAs may adopt alternative trust models and verification mechanisms as defined in their Attestation Rulebooks. The Truvity EUDIW Connector automates trust verification on both sides of the presentation flow. #### The trust model[​](#the-trust-model "Direct link to The trust model") ##### Government as trust anchor[​](#government-as-trust-anchor "Direct link to Government as trust anchor") Member state governments act as trusted third parties that vouch for ecosystem participants. Instead of parties trusting each other directly, all parties trust the governance framework established by the member states. All trust paths lead back to government trust anchors. A credential issued in one member state is trusted in another because both chain back to their respective government authorities, and EU member states recognize each other's trust anchors. ##### Provider registration and notification[​](#provider-registration-and-notification "Direct link to Provider registration and notification") PID Providers and Attestation Providers register with a Registrar in their member state. After successful registration, the member state conditionally notifies the Provider to the European Commission. This notification determines whether the Provider's trust anchors appear in [Trusted Lists or Lists of Trusted Entities (LoTEs)](/eudiw-connector/explanations/trust-revocation/trust-lists.md). ##### RP registration[​](#rp-registration "Direct link to RP registration") As a Relying Party, you register with a Registrar in your member state. As a result of successful registration, an Access Certificate Authority associated with the Registrar issues X.509 [access certificates](/eudiw-connector/explanations/trust-revocation/certificates.md) for your Relying Party Instances. These certificates authenticate your identity to wallets during a presentation request. The ARF distinguishes between a Relying Party (the legal entity) and Relying Party Instances (the technical systems that interact with Wallet Units). A single Relying Party can operate multiple Relying Party Instances, for example for load distribution or business continuity. Each Relying Party Instance receives its own access certificate. note Access certificates authenticate the RP's identity. They do not indicate which data the RP intends to request. That information is provided by registration certificates or the Registrar's online service. See [certificates](/eudiw-connector/explanations/trust-revocation/certificates.md) for details on the distinction between access certificates and registration certificates. #### Trust infrastructure[​](#trust-infrastructure "Direct link to Trust infrastructure") The trust model relies on a hierarchical infrastructure of [trust lists](/eudiw-connector/explanations/trust-revocation/trust-lists.md): 1. **Trust anchors**: Member state authorities maintain trust anchors that are trusted unconditionally within the ecosystem. 2. **Commission trust infrastructure**: The European Commission maintains a common trust infrastructure that enables discovery of all Trusted Lists and LoTEs in the ecosystem. 3. **Trusted Lists and LoTEs**: Each member state publishes Trusted Lists (for QEAA Providers and PuB-EAA Providers) and Lists of Trusted Entities (for PID Providers, Wallet Providers, Access Certificate Authorities, and Providers of registration certificates). Access Certificate Authority trust anchors are published in a LoTE. Wallet Units use these trust anchors to verify the certificate chains of access certificates presented by Relying Parties. To verify a credential or request, systems build a chain of trust from the entity's certificate up to a trust anchor. If the chain is valid and the trust anchor appears in the relevant Trusted List or LoTE, the entity is considered trusted. #### RP-to-wallet trust[​](#rp-to-wallet-trust "Direct link to RP-to-wallet trust") When you request credentials, the wallet must verify your identity to prevent phishing and unauthorized data access. The connector signs your authorization request using the private key associated with your X.509 access certificate. The wallet validates this signature and checks your certificate chain against the trust anchors published in the Access Certificate Authority's LoTE. The wallet also validates the revocation status of every certificate in the trust chain, including the access certificate, any intermediate certificates, and potentially the trust anchor itself. If any certificate in the chain is invalid or revoked, the wallet blocks the request. To protect the privacy of the response, the connector generates [ephemeral encryption keys](/eudiw-connector/explanations/privacy-security/encryption-key-management.md) for each request. The wallet encrypts its response using the ephemeral public key, ensuring only the requesting Relying Party can read it. #### Wallet-to-RP trust[​](#wallet-to-rp-trust "Direct link to Wallet-to-RP trust") The connector verifies that credentials presented by wallets are authentic, valid, and belong to the user: * **Issuer signature**: Each credential contains a digital signature from the issuer. The connector verifies this signature to confirm the data has not been tampered with and was issued by a valid authority. * **[Key binding](/eudiw-connector/explanations/privacy-security/key-binding.md)**: The connector verifies that the presenter controls the private key bound to the credential, proving legitimate possession. * **[Revocation checking](/eudiw-connector/explanations/trust-revocation/revocation-mechanisms.md)**: The connector checks the current status of the credential to ensure it has not been revoked by the issuer. * **Trust anchor verification**: The connector verifies that the credential's issuer is recognized by the EU trust framework by resolving the issuer's certificate chain against the LoTL hierarchy. This confirms the issuer holds a valid entry on the appropriate trust list for the credential category. See [LoTL trust verification](/eudiw-connector/explanations/trust-revocation/lotl-verification.md) for details. #### Trust in different environments[​](#trust-in-different-environments "Direct link to Trust in different environments") The trust model adapts to the deployment environment: * **Production**: Uses CA-issued certificates from member state accredited Registrars. The trust chain links back to official government trust anchors published in Trusted Lists and LoTEs. * **Sandbox**: Uses self-signed certificates that you generate for development and testing. These allow you to test the full flow without requiring official registration. In this mode, the wallet or test tool must be configured to trust the self-signed certificates explicitly. #### Further reading[​](#further-reading "Direct link to Further reading") * [Certificates](/eudiw-connector/explanations/trust-revocation/certificates.md)—the X.509 certificates used for trust establishment * [Trust lists](/eudiw-connector/explanations/trust-revocation/trust-lists.md)—the registries that publish authorized entities * [LoTL trust verification](/eudiw-connector/explanations/trust-revocation/lotl-verification.md)—how the connector verifies credential issuers against the EU trust hierarchy * [Revocation mechanisms](/eudiw-connector/explanations/trust-revocation/revocation-mechanisms.md)—how credential validity is checked --- ### Trust lists Trust lists are the foundation of the EUDI Wallet ecosystem's trust model. They publish trust anchors for authorized entities, enabling the Truvity EUDIW Connector to verify credential issuers across borders. #### Trusted Lists and Lists of Trusted Entities[​](#trusted-lists-and-lists-of-trusted-entities "Direct link to Trusted Lists and Lists of Trusted Entities") The [Architecture Reference Framework (ARF)](/eudiw-connector/explanations/standards/arf-overview.md) distinguishes between two types of registries that serve different categories of entities in the EUDI ecosystem. **Trusted Lists** use the ETSI TS 119 612 format and cover two categories of entity under different legal bases: * **QEAA Providers**: Qualified Electronic Attestation of Attributes Providers, listed under Article 22 of the [eIDAS Regulation](/eudiw-connector/explanations/standards/eidas-2-requirements.md) as qualified trust service providers. * **PuB-EAA Providers**: Public-sector bodies (or entities designated to act on their behalf) that issue attestations under a specific legal basis, listed under Article 45f of the eIDAS Regulation after passing a conformity assessment. **Lists of Trusted Entities (LoTEs)** cover entities that are not trust service providers but still require published trust anchors: * **PID Providers**: Government agencies authorized to issue Personal Identification Data. * **Wallet Providers**: Organizations that provide EUDI Wallet solutions. * **Access Certificate Authorities**: Entities that issue access certificates to Relying Parties. * **Providers of registration certificates**: Entities that issue registration certificates describing an organization's registered scope. Both Trusted Lists and LoTEs serve the same purpose: publishing trust anchors so that ecosystem participants can verify each other. However, they have different legal bases and governance requirements. note There is no Trusted List or LoTE for Relying Parties. RP registration is a separate legal mechanism under Article 5b of eIDAS 2.0—member states maintain national RP registers for transparency and data protection purposes, not for trust-anchor publication. Instead, Relying Parties are authenticated through access certificates issued by Access Certificate Authorities whose trust anchors are published in a LoTE. See [certificates](/eudiw-connector/explanations/trust-revocation/certificates.md) for details on access certificates. #### Discovery through the Commission's trust infrastructure[​](#discovery-through-the-commissions-trust-infrastructure "Direct link to Discovery through the Commission's trust infrastructure") The European Commission maintains a common trust infrastructure that enables any entity in the EUDI Wallet ecosystem to discover all Trusted Lists and LoTEs. Each member state's Trusted List or LoTE Provider signs and publishes its lists, then makes the URLs available through this infrastructure. This federated model respects national sovereignty while ensuring EU-wide interoperability. Each member state maintains its own lists, and the Commission's infrastructure provides a single discovery point for all of them. #### Trust verification[​](#trust-verification "Direct link to Trust verification") When your app receives a presentation through the connector, the trust verification follows these steps: 1. The Relying Party discovers the relevant Trusted Lists and LoTEs through the Commission's common trust infrastructure. 2. The Relying Party obtains trust anchors for PID Providers and Attestation Providers from these lists. 3. When verifying a credential, the Relying Party uses the trust anchor to verify the Provider's signature, possibly through intermediate certificates in the chain. ##### Verification paths by attestation category[​](#verification-paths-by-attestation-category "Direct link to Verification paths by attestation category") The trust verification path differs depending on the type of attestation: * **PIDs and QEAAs**: The Relying Party verifies the Provider's signature using trust anchors obtained directly from a LoTE or Trusted List. * **PuB-EAAs**: The credential's certificate chain includes a QTSP-issued qualified certificate as an intermediate. The Relying Party verifies the full chain up to the PuB-EAA Provider's own trust anchor published on the national Trusted List, not against the QTSP's entry. * **Non-qualified EAAs**: The applicable Attestation Rulebook defines how the Relying Party obtains the relevant trust anchor. These attestations may use domain-specific trust mechanisms. #### Automated verification[​](#automated-verification "Direct link to Automated verification") The EUDIW Connector automates this verification process. When your app receives a presentation (for example, a PID or driver's license), the connector verifies the trust chain, confirms the issuer is authorized, and checks that the issuer's entry is active and not revoked. The connector resolves trust dynamically from the EU LoTL hierarchy—fetching, verifying, and caching the trust lists to determine whether each credential's issuer is recognized for the category it claims to issue. For the full explanation of how the connector resolves trust per credential category, including verification paths and failure reasons, see [LoTL trust verification](/eudiw-connector/explanations/trust-revocation/lotl-verification.md). #### Standards[​](#standards "Direct link to Standards") The trust list infrastructure in the EUDI ecosystem is governed by two ETSI standards: * **ETSI TS 119 612 v2.4.1** defines the format, semantics, and access mechanisms for Trusted Lists. The current version (TLv6) has been mandatory since April 29, 2026. * **ETSI TS 119 602 v1.1.1** defines the format for Lists of Trusted Entities, with dedicated annexes per entity category (PID Provider, Wallet Provider, Access Certificate Authority, Provider of registration certificates). #### Further reading[​](#further-reading "Direct link to Further reading") * [LoTL trust verification](/eudiw-connector/explanations/trust-revocation/lotl-verification.md)—how the connector verifies credential issuers against the EU trust list hierarchy * [Certificates](/eudiw-connector/explanations/trust-revocation/certificates.md)—the X.509 certificates used for trust establishment * [Trust establishment](/eudiw-connector/explanations/trust-revocation/trust-establishment.md)—the overall trust model in the EUDI ecosystem * [Compliance and regulations](/eudiw-connector/overview/compliance-regulations.md)—regulatory context for trust requirements --- ### Account Ownership Credential (AOC) issuance When a customer opens a bank account, the bank verifies their identity and establishes an account relationship. Traditionally, proving that relationship later—for login, transactions, or third-party verification—relies on passwords, SMS codes, or physical tokens. An Account Ownership Credential (AOC) replaces these mechanisms by binding the account relationship to a cryptographic key in the customer's EUDI Wallet. The bank issues the AOC after account opening, and the customer presents it whenever they need to prove they own the account. #### Flow overview[​](#flow-overview "Direct link to Flow overview") Your organization acts as the credential issuer. After completing identity verification and opening the account, you create a credential offer containing the account attributes. The Truvity EUDIW Connector handles the protocol exchange with the customer's wallet, signs the credential, and delivers the result to your callback. The flow works as follows: 1. The customer completes identity verification and opens a bank account. 2. Your backend creates a credential offer with the account attributes. 3. The connector generates a credential offer URI and returns it to your backend. 4. Your app displays a QR code (cross-device) or triggers a deep link (same-device). 5. The customer opens their EUDI Wallet and scans the QR code or taps the link. 6. The wallet retrieves issuer metadata, exchanges the pre-authorized code for an access token, and requests the credential. 7. The connector signs the credential, delivers it to the wallet, and sends a callback to your backend. 8. Your backend updates the account status to reflect that the AOC has been issued. #### Business context[​](#business-context "Direct link to Business context") An AOC addresses three problems that banks face after account opening. ##### Proving account ownership digitally[​](#proving-account-ownership-digitally "Direct link to Proving account ownership digitally") Customers need to prove they hold an account for scenarios like onboarding with a new financial service, authorizing a direct debit, or verifying their identity with a third party. An AOC provides a standardized, cryptographically verifiable proof that doesn't depend on paper statements or bank-specific portals. ##### Enabling passwordless authentication[​](#enabling-passwordless-authentication "Direct link to Enabling passwordless authentication") Once the AOC is in the customer's wallet, it can serve as the authentication credential for future logins. Instead of entering a password, the customer presents the AOC and proves possession of the associated private key. This eliminates password databases and the attack surface they create. ##### Reducing fraud through cryptographic binding[​](#reducing-fraud-through-cryptographic-binding "Direct link to Reducing fraud through cryptographic binding") The AOC is bound to a specific key pair in the customer's wallet. Only the holder of the private key can present the credential, which prevents credential sharing and the use of stolen credentials—risks that exist with passwords and one-time codes. Replay protection is provided separately by the nonce/challenge mechanism during verification, which ensures each presentation is fresh and cannot be reused. #### Relationship to passwordless authentication[​](#relationship-to-passwordless-authentication "Direct link to Relationship to passwordless authentication") The AOC issued during account opening is the same credential verified during [passwordless authentication](/eudiw-connector/explanations/use-cases/authentication.md). This creates a complete credential lifecycle: 1. **Issuance**—the bank issues the AOC to the customer's wallet after account opening. 2. **Storage**—the wallet stores the AOC alongside other credentials. 3. **Presentation**—the customer presents the AOC when logging in or proving account ownership. 4. **Verification**—the bank (or another Relying Party) verifies the AOC using the connector. This means a single integration covers both issuance and authentication. The bank issues the credential once and verifies it on every subsequent interaction. #### Privacy and security[​](#privacy-and-security "Direct link to Privacy and security") ##### Selective disclosure of account attributes[​](#selective-disclosure-of-account-attributes "Direct link to Selective disclosure of account attributes") The AOC supports selective disclosure. When the customer presents the credential, they can share only the attributes the Relying Party needs. For example, a third-party service verifying account ownership might receive the account holder name and bank name without seeing the full account number. ##### Ephemeral data model during issuance[​](#ephemeral-data-model-during-issuance "Direct link to Ephemeral data model during issuance") The connector uses an [ephemeral data model](/eudiw-connector/explanations/privacy-security/ephemeral-data-model.md) during issuance. Account attributes are held in memory only long enough to sign the credential and deliver it to the wallet. After the credential is issued and the callback is delivered, the connector purges the claim data. No customer attributes persist in the connector. ##### Key binding[​](#key-binding "Direct link to Key binding") The credential is cryptographically bound to the customer's wallet key pair during issuance. Only the holder of the corresponding private key can present the AOC. This binding is verified every time the credential is presented, ensuring that a stolen or copied credential is useless without the private key. See [device binding](/eudiw-connector/explanations/privacy-security/key-binding.md) for details on how key binding works. #### Further reading[​](#further-reading "Direct link to Further reading") * [Build an AOC issuance flow](/eudiw-connector/tutorials/aoc-issuance-tutorial.md)—step-by-step tutorial for issuing your first AOC * [Implement AOC issuance](/eudiw-connector/how-to-guides/integration-scenarios/aoc-issuance.md)—production-ready integration guide for AOC issuance in a banking app * [Authentication](/eudiw-connector/explanations/use-cases/authentication.md)—how the AOC enables passwordless authentication after issuance * [OID4VCI protocol](/eudiw-connector/explanations/standards/oid4vci-protocol.md)—how the OID4VCI protocol enables credential issuance between the connector and EUDI Wallets --- ### Authentication Passwordless authentication using EUDI Wallet credentials replaces passwords with cryptographic proofs. Instead of "something you know," users authenticate by proving they possess a valid credential and control its associated private key. This approach eliminates password databases, resists phishing, and improves user experience. #### Prerequisites[​](#prerequisites "Direct link to Prerequisites") The authentication flow requires a credential containing an Account ID to already exist in the user's wallet. In Truvity's demo implementation, this credential is an Account Ownership Credential (AOC). Your organization defines the credential type and schema used for authentication in your own deployment. The credential is typically issued during an initial onboarding or registration flow (for example, after completing Know Your Customer (KYC) verification). #### Flow overview[​](#flow-overview "Direct link to Flow overview") Your organization acts as the Relying Party. You request the authentication credential from the user's wallet, and the Truvity EUDIW Connector handles the protocol exchange, verification, and result delivery. The flow works as follows: 1. The user initiates login in your app. 2. Your app creates a presentation request for the authentication credential. 3. The connector generates an authorization request and returns a URI. 4. Your app displays a QR code (cross-device) or triggers a deep link (same-device). 5. The user opens their EUDI Wallet, reviews the request, and approves with biometric authentication. 6. The wallet signs a challenge with the credential's private key and submits the encrypted response. 7. The connector decrypts, verifies the signature and key binding, and delivers the result to your [callback](/eudiw-connector/explanations/architecture/connector-architecture.md). 8. Your app matches the Key Binding Key Identifier (kbKeyId) to the user's account and establishes a session. #### Recognizing returning users[​](#recognizing-returning-users "Direct link to Recognizing returning users") The Key Binding Key Identifier (kbKeyId) is a stable identifier derived from the credential's proof-of-possession key. It remains consistent across sessions for the same credential, allowing you to recognize returning users without storing personal data. During the initial registration flow, you associate the kbKeyId with the user's account. On subsequent logins, the connector includes the kbKeyId in the callback, and your app matches it to the existing account. #### Trust and security[​](#trust-and-security "Direct link to Trust and security") ##### Key binding[​](#key-binding "Direct link to Key binding") The wallet signs a unique challenge (nonce) with the private key associated with the credential. The connector verifies this signature, proving that the presenter is the same entity that was issued the credential. This is stronger than password-based authentication because the private key never leaves the user's device. ##### Service authentication[​](#service-authentication "Direct link to Service authentication") The connector signs the authorization request using your X.509 access certificate. The wallet checks this certificate and displays your organization's verified name to the user before they consent. This prevents phishing because the user can confirm they're authenticating with the correct service. ##### Transactional data[​](#transactional-data "Direct link to Transactional data") You can include contextual information (for example, "Login to Customer Portal") in the presentation request. The wallet displays this to the user and cryptographically binds it to the authentication proof, preventing the proof from being replayed in a different context. #### Privacy and data minimization[​](#privacy-and-data-minimization "Direct link to Privacy and data minimization") Authentication requests typically require minimal data: the credential with its Account ID and the key binding proof. You don't need to request personal attributes like name or date of birth for login if the kbKeyId is sufficient to identify the user. The connector uses an [ephemeral data model](/eudiw-connector/explanations/privacy-security/ephemeral-data-model.md). Credential data is verified in memory, delivered to your callback, and then deleted. #### Integration patterns[​](#integration-patterns "Direct link to Integration patterns") ##### Cross-device flow[​](#cross-device-flow "Direct link to Cross-device flow") Common for desktop web apps. The user visits your website, scans a QR code with their EUDI Wallet, and your backend receives the authentication result through the callback. ##### Same-device flow[​](#same-device-flow "Direct link to Same-device flow") Common for mobile apps. The user taps "Sign in with Wallet," the operating system opens the EUDI Wallet through a deep link, the user approves, and the wallet redirects back to your app. #### Further reading[​](#further-reading "Direct link to Further reading") * [Device binding](/eudiw-connector/explanations/privacy-security/key-binding.md)—how cryptographic key binding proves the presenter legitimately possesses the credential * [Connector architecture](/eudiw-connector/explanations/architecture/connector-architecture.md)—system components, data flow, and how the connector delivers results to your callback * [OID4VP protocol](/eudiw-connector/explanations/standards/oid4vp-protocol.md)—how the OID4VP protocol enables credential verification between wallets and Relying Parties --- ### Know Your Customer (KYC) The KYC flow uses EUDI Wallet credentials for identity verification during customer onboarding. Instead of manual document uploads, your app requests government-issued Personal Identification Data (PID) from the user's wallet, verifying identity through cryptographic proofs. This applies to any regulated onboarding scenario—opening a bank account, purchasing an insurance policy, registering for a government service, or any process that requires verified identity. #### Flow overview[​](#flow-overview "Direct link to Flow overview") Your organization acts as the Relying Party. You request specific identity attributes from the user's wallet, and the Truvity EUDIW Connector handles the protocol exchange, verification, and result delivery. The flow works as follows: 1. The user initiates onboarding in your app. 2. Your app creates a presentation request specifying the required identity attributes. 3. The connector generates an authorization request and returns a URI. 4. Your app displays a QR code (cross-device) or triggers a deep link (same-device). 5. The user opens their EUDI Wallet, reviews the request, and consents to share their data. 6. The wallet submits an encrypted presentation response to the connector. 7. The connector decrypts, verifies signatures and trust chains, and delivers the result to your [callback](/eudiw-connector/explanations/architecture/connector-architecture.md). 8. Your app completes the onboarding process. #### Trust and security[​](#trust-and-security "Direct link to Trust and security") The flow relies on multiple layers of cryptographic verification. ##### Trusted issuers[​](#trusted-issuers "Direct link to Trusted issuers") The PID is signed by a government issuer. The connector verifies the issuer's signature and certificate chain, ensuring the data comes from a valid government source. ##### Service authentication[​](#service-authentication "Direct link to Service authentication") The connector signs the authorization request using your X.509 access certificate. The wallet checks this certificate to display your organization's verified name to the user before they consent, reducing phishing risks. ##### Revocation checking[​](#revocation-checking "Direct link to Revocation checking") The connector checks whether the credential has been revoked by the issuer. Revoked credentials are rejected even if their expiration date has not passed. #### Privacy and data minimization[​](#privacy-and-data-minimization "Direct link to Privacy and data minimization") The flow supports GDPR data minimization principles. You request only the specific attributes necessary for KYC, such as name and date of birth, omitting fields that are not required by regulation. The user shares less data than they would by presenting a physical ID card. The connector uses an [ephemeral data model](/eudiw-connector/explanations/privacy-security/ephemeral-data-model.md). Credential data is verified in memory, delivered to your callback, and then deleted. No user attributes persist in the connector. #### Integration patterns[​](#integration-patterns "Direct link to Integration patterns") ##### Cross-device flow[​](#cross-device-flow "Direct link to Cross-device flow") Common for desktop web apps. The user initiates onboarding on your website, scans a QR code with their EUDI Wallet, and your backend receives the verification result through the callback. ##### Same-device flow[​](#same-device-flow "Direct link to Same-device flow") Common for mobile apps. The user taps a button in your app, the operating system opens the EUDI Wallet through a deep link, the user approves the request, and the wallet redirects back to your app. #### Further reading[​](#further-reading "Direct link to Further reading") * [Build a KYC verification flow](/eudiw-connector/tutorials/kyc-tutorial.md)—step-by-step tutorial for verifying identity credentials during onboarding * [Implement KYC verification](/eudiw-connector/how-to-guides/integration-scenarios/kyc-verification.md)—production-ready integration guide for KYC identity verification * [Connector architecture](/eudiw-connector/explanations/architecture/connector-architecture.md)—how the connector processes credentials and delivers results via callback * [OID4VP protocol](/eudiw-connector/explanations/standards/oid4vp-protocol.md)—how the OID4VP protocol enables credential verification between wallets and Relying Parties * [Selective disclosure](/eudiw-connector/explanations/privacy-security/selective-disclosure.md)—how selective disclosure enables privacy-preserving credential sharing --- ### Getting started These guides walk you from zero to a working integration with the Truvity EUDIW Connector. Start with verification, then add issuance. * **[Verify a credential](/eudiw-connector/getting-started/verify-credentials.md)**—Set up the connector, create your first presentation request, and receive verified attributes from an EUDI Wallet. * **[Issue a credential](/eudiw-connector/getting-started/issue-credentials.md)**—Configure an Issuer Signing Certificate and Type Metadata, then issue your first credential to a wallet. Each guide is self-contained and includes all setup steps. The only prerequisite is a deployed connector instance. --- ### Issue a credential Create a credential offer, display it to a user, and deliver a signed credential to their EUDI Wallet. This guide covers the minimal steps to complete an issuance flow. Before you begin * Completed the [verification quickstart](/eudiw-connector/getting-started/verify-credentials.md) (your connector has a certificate and callback configured) The connector implements [OID4VCI](/eudiw-connector/explanations/standards/oid4vci-protocol.md) using the [pre-authorized code flow](/eudiw-connector/explanations/standards/oid4vci-protocol.md#pre-authorized-code-flow) under the [High Assurance Interoperability Profile (HAIP)](/eudiw-connector/explanations/standards/haip.md). The connector's built-in [Authorization Server](/eudiw-connector/explanations/standards/oid4vci-protocol.md) issues access tokens to wallets using [DPoP](/eudiw-connector/explanations/privacy-security/dpop.md) (sender-constrained tokens). You don't need to configure protocol options—the connector applies HAIP-compliant settings by default. #### Set up for issuance[​](#set-up-for-issuance "Direct link to Set up for issuance") ##### Generate an Issuer Signing Certificate[​](#generate-an-issuer-signing-certificate "Direct link to Generate an Issuer Signing Certificate") The Issuer Signing Certificate signs the credentials your connector issues—it must use a separate key from the access certificate. ```bash # Generate an EC P-256 private key for credential signing openssl ecparam -genkey -name prime256v1 -noout \ -out ./certs/signing-key.pem # Generate a self-signed X.509 certificate (valid for 365 days) openssl req -new -x509 -key ./certs/signing-key.pem \ -out ./certs/signing-cert.pem \ -days 365 \ -subj "/CN=My Organization Issuer/O=My Organization/C=DE" # Configure the connector export CONNECTOR_CERTIFICATES_SIGNING_CERT_PATH=./certs/signing-cert.pem export CONNECTOR_CERTIFICATES_SIGNING_KEY_PATH=./certs/signing-key.pem ``` For production certificates, see [Manage certificates](/eudiw-connector/how-to-guides/certificates.md). ##### Configure a credential type[​](#configure-a-credential-type "Direct link to Configure a credential type") Type Metadata defines what claims a credential contains and how wallets display it. ```json { "vct": "https://issuer.example.com/oidc4vci/types/IdentityCredential", "display": [ { "lang": "en-US", "name": "Identity Credential" } ], "claims": [ { "path": ["given_name"], "sd": "allowed", "display": [{ "lang": "en-US", "label": "Given name" }] }, { "path": ["family_name"], "sd": "allowed", "display": [{ "lang": "en-US", "label": "Family name" }] } ] } ``` Save this as `type-metadata/identity-credential.json`, then configure the connector: ```bash export CONNECTOR_CREDENTIAL_CONFIGURATIONS_IDENTITYCREDENTIAL_VCT_SOURCE=local export CONNECTOR_CREDENTIAL_CONFIGURATIONS_IDENTITYCREDENTIAL_VCT_FILEPATH=./type-metadata/identity-credential.json export CONNECTOR_CREDENTIAL_CONFIGURATIONS_IDENTITYCREDENTIAL_SCOPE=identity_credential ``` For the full reference, see [Configure credential types](/eudiw-connector/how-to-guides/credential-type-configuration.md). #### Create a credential offer[​](#create-a-credential-offer "Direct link to Create a credential offer") Call `POST /offers` on the management API with a `credential_configuration_id` and the `claims` to include in the credential. The `credential_configuration_id` must match a credential type configured in the connector's [Type Metadata](/eudiw-connector/how-to-guides/credential-type-configuration.md). note The `credential_configuration_id`, claim names, and claim values in this example are illustrative. In production, use the `credential_configuration_id` and claims defined in your Type Metadata configuration. * cURL ```bash curl -X POST http://connector:8081/offers \ -H "Content-Type: application/json" \ -d '{ "credential_configuration_id": "IdentityCredential", "claims": { "given_name": "Erika", "family_name": "Mustermann" } }' ``` Example response (`201 Created`): ```json { "offer_id": "abc123def456", "credential_offer_uri": "openid-credential-offer://?credential_offer_uri=https%3A%2F%2Fissuer.example.com%2Foidc4vci%2Foffers%2Fabc123def456" } ``` Store the `offer_id` to correlate with the issuance callback later. Render `credential_offer_uri` as a QR code for cross-device flows or redirect the user to it for same-device flows. The response contains: * `offer_id`—a correlation token to match the issuance callback with this offer. * `credential_offer_uri`—an `openid-credential-offer://` URI for the wallet. Render it as a QR code or use it as a deep link. You can optionally include a `tx_code` object in the request to require transaction code authorization. See [Use transaction codes](/eudiw-connector/how-to-guides/tx-code.md) for details. #### Handle the issuance callback[​](#handle-the-issuance-callback "Direct link to Handle the issuance callback") Implement a callback endpoint that receives the issuance event from the connector. The event's `status` field indicates the issuance outcome. * cURL ```bash # Simulate an ISSUED callback for testing curl -X POST https://example.com:3000/callback/issuance \ -H "Content-Type: application/json" \ -d '{ "eventId": "abc123def456", "status": "ISSUED", "offerId": "abc123def456" }' ``` ```bash # Simulate a FAILED callback for testing curl -X POST https://example.com:3000/callback/issuance \ -H "Content-Type: application/json" \ -d '{ "eventId": "abc123def456", "status": "FAILED", "offerId": "abc123def456", "errorDetails": "issuer service error: signing key validation failed" }' ``` The issuance callback has four possible statuses: * `OFFER_CREATED`—the offer was created and the session is active. Use for audit logging or to start a timeout timer. * `ISSUED`—the credential was successfully issued to the wallet. * `FAILED`—issuance failed. The `errorDetails` field describes the reason. * `EXPIRED`—the session expired before the wallet completed the flow. Create a new offer if the user still needs the credential. Use the `offerId` field to correlate the callback with the original offer. For the complete list of issuance statuses and payload fields, see the [callback events reference](/eudiw-connector/reference/callback-events.md). #### Next steps[​](#next-steps "Direct link to Next steps") * [Verify a credential](/eudiw-connector/getting-started/verify-credentials.md)—create a presentation request and receive verified attributes from a wallet * [Build an AOC issuance flow](/eudiw-connector/tutorials/aoc-issuance-tutorial.md)—end-to-end tutorial for issuing Account Ownership Credentials * [Configure credential types](/eudiw-connector/how-to-guides/credential-type-configuration.md)—set up Type Metadata for the credential types your connector issues * [Use transaction codes](/eudiw-connector/how-to-guides/tx-code.md)—require a PIN or code before the wallet can claim the credential #### Further reading[​](#further-reading "Direct link to Further reading") * [Connector architecture](/eudiw-connector/explanations/architecture/connector-architecture.md)—how the connector processes requests and delivers results * [OID4VCI protocol](/eudiw-connector/explanations/standards/oid4vci-protocol.md)—the issuance protocol the connector implements * [Callback events](/eudiw-connector/reference/callback-events.md)—all callback event statuses and payload fields --- ### Getting started Get up and running with the Truvity EUDIW Connector in minutes. This guide walks you through the credential verification flow and helps you create your first presentation request. #### How it works[​](#how-it-works "Direct link to How it works") A credential verification flow involves five steps: 1. **Your backend creates a presentation request.** You call `POST /oidc4vp` on the internal management API (port 8081) with a [DCQL](/eudiw-connector/explanations/standards/dcql.md) query specifying the credentials and attributes you need. The connector returns a `state` value for correlation, a `same_device_request_uri` for deep links, and a `cross_device_request_uri` for QR codes. 2. **You display the request URI to the user.** For cross-device flows, render the `cross_device_request_uri` as a QR code. For same-device flows, redirect the user to the `same_device_request_uri` deep link. 3. **The wallet retrieves and displays the request.** The EUDI Wallet fetches the signed authorization request from the connector's public protocol endpoint, verifies your X.509 certificate, and displays a consent screen to the user. 4. **The user approves and the wallet submits the presentation.** The user consents with biometric authentication. The wallet encrypts the presentation and submits it to the connector's public protocol endpoint using the `direct_post.jwt` response mode. 5. **The connector verifies credentials and delivers the result.** The connector decrypts, verifies signatures, checks revocation, and delivers a `PresentedCredentialsEvent` to your [callback](/eudiw-connector/explanations/architecture/connector-architecture.md) endpoint. The connector implements [OID4VP](/eudiw-connector/explanations/standards/oid4vp-protocol.md) under the [High Assurance Interoperability Profile (HAIP)](/eudiw-connector/explanations/standards/haip.md), which defines the required algorithms, response modes, and credential formats for the EUDI Wallet ecosystem. You don't need to configure these protocol options. The connector applies HAIP-compliant settings by default. Before you begin * A deployed Truvity EUDIW Connector instance. The connector is not publicly available—contact to get access. #### Set up your connector[​](#set-up-your-connector "Direct link to Set up your connector") ##### Step 1: Configure your public URL[​](#step-1-configure-your-public-url "Direct link to Step 1: Configure your public URL") The connector needs a publicly reachable URL so wallets can send responses. ```bash export CONNECTOR_BASE_URL=https://connector.example.com ``` ##### Step 2: Generate a test certificate[​](#step-2-generate-a-test-certificate "Direct link to Step 2: Generate a test certificate") The connector uses an X.509 certificate to identify itself to wallets. ```bash mkdir -p ./certs # Generate an EC P-256 private key openssl ecparam -genkey -name prime256v1 -noout \ -out ./certs/access-key.pem # Generate a self-signed X.509 certificate (valid for 365 days) openssl req -new -x509 -key ./certs/access-key.pem \ -out ./certs/access-cert.pem \ -days 365 \ -subj "/CN=My Organization/O=My Organization/C=DE" # Configure the connector to use the certificate export CONNECTOR_CERT_PATH=./certs/access-cert.pem export CONNECTOR_KEY_PATH=./certs/access-key.pem ``` For production certificates, see [Manage certificates](/eudiw-connector/how-to-guides/certificates.md). ##### Step 3: Set up a callback endpoint[​](#step-3-set-up-a-callback-endpoint "Direct link to Step 3: Set up a callback endpoint") The connector delivers verification results to an HTTP endpoint you provide. ```bash # Start a minimal callback server (Node.js) node -e "require('http').createServer((req, res) => { let body = ''; req.on('data', c => body += c); req.on('end', () => { console.log(JSON.parse(body)); res.end('OK'); }); }).listen(3000, () => console.log('Callback listening on :3000'))" ``` ```bash export CONNECTOR_CALLBACK_URL=http://localhost:3000 ``` note For production deployments, see [Manage certificates](/eudiw-connector/how-to-guides/certificates.md) and [Going to production](/eudiw-connector/how-to-guides/going-to-production.md). #### Create a presentation request[​](#create-a-presentation-request "Direct link to Create a presentation request") Call `POST /oidc4vp` on the management API with a DCQL query. This example requests a [PID](/eudiw-connector/reference/glossary.md#eudi-wallet-ecosystem) (Personal Identification Data) credential with basic identity attributes. The `dc+sd-jwt` format is the [SD-JWT VC](/eudiw-connector/explanations/credential-formats/sd-jwt.md) credential format used in the EUDI ecosystem. note The [VCT](/eudiw-connector/reference/glossary.md#protocols-and-standards) (Verifiable Credential Type) values, requested claims, and credential values in this guide are examples. In production, request the attributes required by your use case and available in the target [attestation scheme](/eudiw-connector/reference/glossary.md#eudi-wallet-ecosystem). Available attributes vary by issuer and member state. * cURL ```bash curl -X POST http://connector:8081/oidc4vp \ -H "Content-Type: application/json" \ -d '{ "dcql_query": { "credentials": [ { "id": "pid", "format": "dc+sd-jwt", "meta": { "vct_values": ["urn:eudi:pid:1"] }, "claims": [ { "path": ["given_name"] }, { "path": ["family_name"] }, { "path": ["birthdate"] } ] } ] } }' ``` Example response: ```json { "state": "abc123", "same_device_request_uri": "openid4vp://?client_id=...&request_uri=https%3A%2F%2Fconnector.example.com%2Foidc4vp%2Fabc123%2Frequest%3Fflow_type%3Dsame-device", "cross_device_request_uri": "openid4vp://?client_id=...&request_uri=https%3A%2F%2Fconnector.example.com%2Foidc4vp%2Fabc123%2Frequest%3Fflow_type%3Dcross-device" } ``` Store the `state` value to correlate with the callback later. Both URIs use the `openid4vp://` scheme with `client_id` and `request_uri` query parameters — pass them to the wallet as-is without parsing. Render `cross_device_request_uri` as a QR code or redirect the user to `same_device_request_uri` for same-device flows. The response contains: * `state`—a correlation token to match the callback with this request. * `same_device_request_uri`—an `openid4vp://` URI for same-device flows. Pass the full URI to the wallet as a deep link. * `cross_device_request_uri`—an `openid4vp://` URI to render as a QR code for cross-device flows. #### Handle the callback[​](#handle-the-callback "Direct link to Handle the callback") Implement a callback endpoint that receives the `PresentedCredentialsEvent` from the connector. The event's `status` field indicates the verification outcome. * cURL ```bash # Simulate a FULFILLED callback for testing curl -X POST http://localhost:3000/callback \ -H "Content-Type: application/json" \ -d '{ "status": "FULFILLED", "state": "abc123", "responseCode": "8k5CwzAseoGVK_bHQQJWMw", "credentials": { "pid": [ { "issuer": "https://issuer.example.com", "claims": { "given_name": "Erika", "family_name": "Mustermann", "birthdate": "1964-08-12" }, "signatureIsValid": true, "supportRevocation": false, "supportTrustAnchor": true, "isTrusted": false, "isCertificateRevoked": false, "kbKeyId": "KrXxHnYsf-Inp0hW1M6r...", "kbSignatureIsValid": true } ] }, "credentialsRaw": { "pid": [ { "claims": "eyJiaXJ0aGRhdGUiOiIx...", "issuer": "https://issuer.example.com", "kbKeyId": "KrXxHnYsf-Inp0hW1M6r..." } ] } }' ``` The `credentials` and `credentialsRaw` fields are absent for `REJECTED`, `EXPIRED`, `PROCESSING_ERROR`, and `VERIFICATION_FAILED` statuses. The `errorDetails` field is present for `REJECTED`, `PROCESSING_ERROR`, and `VERIFICATION_FAILED` statuses. For same-device flows, the event includes a `responseCode` field to correlate the browser redirect with the callback. For the complete list of statuses and error codes, see the [callback events reference](/eudiw-connector/reference/callback-events.md). Data handling responsibility You are responsible for applying your own data retention and access control policies to credential data received through callbacks. The connector does not persist credential data after delivering the callback. #### Next steps[​](#next-steps "Direct link to Next steps") * [KYC verification](/eudiw-connector/how-to-guides/integration-scenarios/kyc-verification.md)—verify customer identity using PID credentials * [Passwordless authentication](/eudiw-connector/how-to-guides/integration-scenarios/passwordless-authentication.md)—replace passwords with key binding proof #### Further reading[​](#further-reading "Direct link to Further reading") * [Connector architecture](/eudiw-connector/explanations/architecture/connector-architecture.md)—how the connector processes requests and delivers results * [OID4VP protocol](/eudiw-connector/explanations/standards/oid4vp-protocol.md)—the verification protocol the connector implements * [Error codes](/eudiw-connector/reference/error-codes.md)—wallet-facing HTTP error responses * [Callback events](/eudiw-connector/reference/callback-events.md)—Presented Credentials Event statuses and payload fields --- ### Manage certificates This guide shows you how to generate self-signed certificates for development and configure production certificates for the Truvity EUDIW Connector. [Certificates](/eudiw-connector/explanations/trust-revocation/certificates.md) authenticate the connector to EUDI Wallets and establish your identity as a registered Relying Party or credential issuer. Prerequisites * A running connector instance, or one you are preparing to deploy * A tool that can generate EC P-256 keys and X.509 certificates (the examples below use `openssl`, available by default on macOS and most Linux distributions) * For production: an X.509 access certificate from a Certificate Authority (CA) or member state registrar #### Overview[​](#overview "Direct link to Overview") The connector uses certificates for both verification and issuance. This guide covers all certificate types. **Verification** requires two certificate types: * **Access certificates** are X.509 certificates that authenticate the connector to wallets. The connector includes the access certificate in the `x5c` header of the signed authorization request JWT, as required by the [HAIP profile](/eudiw-connector/explanations/standards/haip.md). The wallet verifies your access certificate against [trust lists](/eudiw-connector/explanations/trust-revocation/trust-lists.md) before showing the consent screen to the user. * **Registration certificates** are signed data objects (JWT or CWT format, not X.509) that prove your organization's registration as a Relying Party with member state authorities. Whether a registration certificate is required depends on the member state's policy. You obtain these through the member state's registration process when required. **Issuance** requires additional certificates: * **Issuer Signing Certificate** signs the credentials your organization issues (covered in [Issuance certificates](#issuance-certificates) below) * **Access Certificate** (for issuance) signs the credential issuer metadata * **Registration Certificate** (optional) declares which credential types you can issue You are responsible for obtaining, renewing, and rotating your access certificate. The connector loads the certificate and private key from the file system (typically Kubernetes secret volumes) at startup. **Time to implement**: 30 minutes for test certificates, 1-2 days for production certificates (depending on CA turnaround). #### Step 1: Generate self-signed test certificates[​](#step-1-generate-self-signed-test-certificates "Direct link to Step 1: Generate self-signed test certificates") Generate a self-signed EC P-256 key pair and X.509 certificate for development. EC P-256 is required because the HAIP profile mandates ES256 for signing authorization request JWTs. You can use any tool that produces PEM-format EC P-256 keys—the example below uses `openssl`. ```bash # Generate an EC P-256 private key openssl ecparam -genkey -name prime256v1 -noout \ -out ./certs/access-key.pem # Generate a self-signed X.509 certificate (valid for 365 days) openssl req -new -x509 -key ./certs/access-key.pem \ -out ./certs/access-cert.pem \ -days 365 \ -subj "/CN=My Organization/O=My Organization/C=DE" ``` The commands generate: * An EC P-256 private key in PEM format * A self-signed X.509 certificate in PEM format with a one-year expiration Verify the generated certificate: ```bash openssl x509 -in ./certs/access-cert.pem -text -noout ``` Configure the connector to load the certificate and key by setting the file paths in the connector's environment variables: * `CONNECTOR_CERT_PATH`—path to the PEM-encoded X.509 certificate file * `CONNECTOR_KEY_PATH`—path to the PEM-encoded private key file For example, if you placed the files in `./certs/`: ```bash export CONNECTOR_CERT_PATH=./certs/access-cert.pem export CONNECTOR_KEY_PATH=./certs/access-key.pem ``` The connector reads these files at startup. #### Step 2: Configure production certificates[​](#step-2-configure-production-certificates "Direct link to Step 2: Configure production certificates") For production, obtain an X.509 access certificate from a CA or your member state's registrar. ##### Obtain the certificate[​](#obtain-the-certificate "Direct link to Obtain the certificate") 1. Generate a Certificate Signing Request (CSR) using the connector's key pair or your own EC P-256 key. The HAIP profile requires ES256, so the key must use the P-256 curve. 2. Submit the CSR to your CA or member state registrar. 3. Receive the signed X.509 certificate in PEM format. ##### Load certificates from Kubernetes secrets[​](#load-certificates-from-kubernetes-secrets "Direct link to Load certificates from Kubernetes secrets") Store the certificate and private key as a Kubernetes secret: ```bash kubectl create secret tls connector-access-cert \ --cert=./certs/access-cert.pem \ --key=./certs/access-key.pem \ -n your-namespace ``` Mount the secret as a volume in the connector's pod and set the environment variables to point to the mounted paths: ```yaml spec: containers: - name: connector env: - name: CONNECTOR_CERT_PATH value: /var/secrets/x509/tls.crt - name: CONNECTOR_KEY_PATH value: /var/secrets/x509/tls.key volumeMounts: - name: x509-certs mountPath: /var/secrets/x509 readOnly: true volumes: - name: x509-certs secret: secretName: connector-access-cert ``` ##### Rotate certificates[​](#rotate-certificates "Direct link to Rotate certificates") When a certificate approaches expiration: 1. Obtain a new certificate from your CA or registrar. 2. Update the Kubernetes secret with the new certificate and key. 3. Restart the connector pod to load the new certificate. Plan certificate rotation before expiration to avoid service interruption. Wallets reject requests signed with expired certificates. #### Issuance certificates[​](#issuance-certificates "Direct link to Issuance certificates") The following certificates are used for credential issuance, in addition to the verification access certificate. ##### Issuer signing certificate[​](#issuer-signing-certificate "Direct link to Issuer signing certificate") The Issuer Signing Certificate is an X.509 certificate used to sign SD-JWT Verifiable Credentials during issuance. The connector includes this certificate in the credential's `x5c` header so that wallets can verify the credential signature against the issuer's certificate chain. Key requirements: * Uses ES256 (P-256), the same curve as the verification access certificate * Must use a **separate key** from the verification access certificate * The PEM certificate file must contain the leaf certificate first, followed by any intermediate certificates, excluding the root. The connector builds the `x5c` header from this chain automatically. * Self-signed certificates are supported for development only ###### Generate a self-signed issuer signing certificate[​](#generate-a-self-signed-issuer-signing-certificate "Direct link to Generate a self-signed issuer signing certificate") Generate a self-signed EC P-256 key pair and certificate for development, following the same pattern as the verification access certificate in [Step 1](#step-1-generate-self-signed-test-certificates). ```bash # Generate an EC P-256 private key for credential signing openssl ecparam -genkey -name prime256v1 -noout \ -out ./certs/signing-key.pem # Generate a self-signed X.509 certificate (valid for 365 days) openssl req -new -x509 -key ./certs/signing-key.pem \ -out ./certs/signing-cert.pem \ -days 365 \ -subj "/CN=My Organization Issuer/O=My Organization/C=DE" ``` Verify the generated certificate: ```bash openssl x509 -in ./certs/signing-cert.pem -text -noout ``` Configure the connector to load the Issuer Signing Certificate and private key: * `CONNECTOR_CERTIFICATES_SIGNING_CERT_PATH`—path to the PEM-encoded Issuer Signing Certificate file * `CONNECTOR_CERTIFICATES_SIGNING_KEY_PATH`—path to the PEM-encoded private key file For example: ```bash export CONNECTOR_CERTIFICATES_SIGNING_CERT_PATH=./certs/signing-cert.pem export CONNECTOR_CERTIFICATES_SIGNING_KEY_PATH=./certs/signing-key.pem ``` The connector reads these files at startup. In production, mount them from Kubernetes secrets following the same pattern as [Step 2](#step-2-configure-production-certificates). Separate keys required The Issuer Signing Certificate and the verification access certificate must use separate keys. Do not reuse the same key pair for both purposes. ##### Access certificate for issuance[​](#access-certificate-for-issuance "Direct link to Access certificate for issuance") The Access Certificate proves the connector's participation in the EUDI ecosystem. In the issuance context, the connector uses the Access Certificate to sign the Credential Issuer Metadata served at `GET /.well-known/openid-credential-issuer`. The Access Certificate for issuance must use a **separate key** from the Issuer Signing Certificate. It may be the same certificate as the verification access certificate or a separate one, depending on your deployment requirements. Configure the connector to load the Access Certificate for metadata signing: * `CONNECTOR_CERTIFICATES_ACCESS_CERT_PATH`—path to the PEM-encoded Access Certificate * `CONNECTOR_CERTIFICATES_ACCESS_KEY_PATH`—path to the PEM-encoded private key for metadata signing For example: ```bash export CONNECTOR_CERTIFICATES_ACCESS_CERT_PATH=/secrets/access/cert.pem export CONNECTOR_CERTIFICATES_ACCESS_KEY_PATH=/secrets/access/key.pem ``` ##### Registration certificate (optional)[​](#registration-certificate-optional "Direct link to Registration certificate (optional)") The Registration Certificate is an optional signed data object that declares the issuer's entitlements—which credential types the issuer is authorized to issue. Not all member states issue registration certificates. Key characteristics: * JWT format (not X.509). The ARF also defines CWT as a possible format, but the connector currently supports JWT only. * Included by value in the Credential Issuer Metadata when available * Obtained through the member state's registration process If you have a Registration Certificate in JWT format, configure the connector to load it: * `CONNECTOR_CERTIFICATES_REGISTRATION_JWT_PATH`—path to the Registration Certificate in JWT format For example: ```bash export CONNECTOR_CERTIFICATES_REGISTRATION_JWT_PATH=/secrets/registration/cert.jwt ``` The connector includes the Registration Certificate in the Credential Issuer Metadata response when this path is configured. #### Testing[​](#testing "Direct link to Testing") * Self-signed certificate generates with `openssl` and the output files are valid PEM * Connector starts and loads the certificate from the configured path * Wallet accepts the connector's authorization request (in test environments with trust list overrides) * Production certificate is recognized by wallets against the member state trust list * Issuer Signing Certificate generates with `openssl` and the output files are valid PEM * Connector loads the Issuer Signing Key and certificate chain at startup * Issued credentials contain the correct `x5c` header with the Issuer Signing Certificate chain * Issuer Signing Certificate and verification access certificate use separate keys #### Troubleshooting[​](#troubleshooting "Direct link to Troubleshooting") ##### Connector fails to start with certificate errors[​](#connector-fails-to-start-with-certificate-errors "Direct link to Connector fails to start with certificate errors") Verify that the certificate and key files are in PEM format and that the key matches the certificate. Run `openssl x509 -in cert.pem -noout -text` to inspect the certificate and `openssl ec -in key.pem -noout` to verify the private key is a valid EC key. ##### Wallet rejects the authorization request[​](#wallet-rejects-the-authorization-request "Direct link to Wallet rejects the authorization request") The wallet validates your certificate against the trust list of the relevant jurisdiction. In development, configure the wallet or test environment to trust your self-signed certificate. In production, verify that your CA-issued certificate is included in the member state's trust list. ##### Certificate expiration[​](#certificate-expiration "Direct link to Certificate expiration") Monitor certificate expiration dates and rotate before they expire. Use `openssl x509 -in cert.pem -noout -enddate` to check the expiration date. ##### Issued credentials fail wallet verification[​](#issued-credentials-fail-wallet-verification "Direct link to Issued credentials fail wallet verification") Verify that the Issuer Signing Certificate PEM file is correctly ordered (leaf certificate first, intermediates next, excluding the root). The connector builds the `x5c` header automatically from the PEM chain. Confirm that the Issuer Signing Key matches the leaf certificate in the chain. ##### Credential Issuer Metadata signature invalid[​](#credential-issuer-metadata-signature-invalid "Direct link to Credential Issuer Metadata signature invalid") The connector signs the Credential Issuer Metadata with the Access Certificate private key. Verify that the Access Certificate and its private key are correctly configured and that the key matches the certificate. Check that the Access Certificate uses a separate key from the Issuer Signing Certificate. #### Next steps[​](#next-steps "Direct link to Next steps") * [Get ready for production](/eudiw-connector/how-to-guides/going-to-production.md)—complete production readiness checklist * [Verify a credential](/eudiw-connector/getting-started/verify-credentials.md)—create your first presentation request * [Configure credential types](/eudiw-connector/how-to-guides/credential-type-configuration.md)—define the credential types your connector can issue #### Further reading[​](#further-reading "Direct link to Further reading") * [Certificates in EUDI](/eudiw-connector/explanations/trust-revocation/certificates.md)—how certificates establish trust in the EUDI ecosystem * [Trust establishment](/eudiw-connector/explanations/trust-revocation/trust-establishment.md)—how wallets verify Relying Party identity * [Connector architecture](/eudiw-connector/explanations/architecture/connector-architecture.md)—system components and security model * [OID4VCI protocol](/eudiw-connector/explanations/standards/oid4vci-protocol.md)—how the issuance protocol uses certificates for credential signing --- ### Configure trust anchor verification This guide shows you how to configure the Truvity EUDIW Connector to verify credential issuers against the EU List of Trusted Lists (LoTL) hierarchy. In LoTL-enabled mode, the connector dynamically resolves whether each credential's issuer is recognized by the EU trust framework, determines the credential category, and reports enriched trust metadata on the callback payload. Static-only mode is available as a fallback for environments without LoTL infrastructure. For conceptual background on how LoTL trust verification works, see [LoTL trust verification](/eudiw-connector/explanations/trust-revocation/lotl-verification.md). Prerequisites * A running connector instance, or one you are preparing to deploy * Access to the connector's configuration (environment variables or configuration file) #### Overview[​](#overview "Direct link to Overview") This guide covers: 1. Configuring LoTL-driven trust resolution (production path) 2. Setting up trust verification policy per credential category 3. Interpreting trust verification results 4. Configuring static-only mode (fallback) 5. Testing and troubleshooting **Time to implement**: 1-2 hours. #### LoTL-enabled mode[​](#lotl-enabled-mode "Direct link to LoTL-enabled mode") Set the trust resolution mode to `lotl` and configure at least one trust list source. ##### Configuration reference[​](#configuration-reference "Direct link to Configuration reference") | Variable | Type | Default | Description | | ----------------------------------- | --------------- | ------------------ | ---------------------------------------------------------------------------------------------------------------- | | `X509_TRUST_RESOLUTION_MODE` | string | `static` | Trust resolution mode. Set to `lotl` for LoTL-enabled mode, `static` for static-only mode. | | `X509_TRUST_LIST_SOURCES` | structured list | (none) | Trust list sources to fetch and verify. See format below. | | `X509_TRUST_STORE_REFRESH_INTERVAL` | duration | `6h` | How often the connector refreshes the trust store from configured sources. | | `X509_STALENESS_WINDOW` | duration | `24h` | Maximum age of cached trust data the connector honors after a fresh fetch fails before failing closed. | | `X509_LOTL_FETCH_TIMEOUT` | duration | `30s` | HTTP timeout for trust list fetch requests. | | `X509_MAX_RESPONSE_BYTES` | int64 | `10485760` (10 MB) | Maximum response body size for trust list fetches. Responses exceeding this limit are treated as fetch failures. | ##### Trust list source configuration[​](#trust-list-source-configuration "Direct link to Trust list source configuration") The `X509_TRUST_LIST_SOURCES` variable configures which trust lists the connector fetches and verifies. Each source specifies a trust list endpoint, its category, and verification parameters. For multi-source deployments, use a configuration file with the following structure: ```yaml # trust_list_sources structured configuration # Each entry defines a trust list source the connector fetches and verifies. trust_list_sources: - category: LoTL endpoint: "https://ec.europa.eu/tools/lotl/eu-lotl.xml" signing_certificates: - "MIICxzCCAa+gAwIBAgI..." # Base64-encoded DER of the LoTL signing certificate refresh_interval: 6h cache_ttl: 24h fallback_mode: cached_trust # fail_closed | cached_trust | cached_trust_with_warning max_response_bytes: 10485760 - category: PID_PROVIDER_LOTE endpoint: "https://trust.pid.bund.de/lote/pid-providers.json" signing_certificates: - "MIICxzCCAa+gAwIBAgI..." # Base64-encoded DER of the German PID LoTE signing cert refresh_interval: 6h cache_ttl: 24h fallback_mode: cached_trust max_response_bytes: 10485760 - category: NATIONAL_TL endpoint: "https://trust.tsl.bnetza.de/TSL-DE.xml" signing_certificates: - "MIICxzCCAa+gAwIBAgI..." # Base64-encoded DER of the German TSL signing cert refresh_interval: 6h cache_ttl: 24h fallback_mode: cached_trust max_response_bytes: 10485760 ``` For single-source deployments, use the flat environment variable convenience fields instead of the structured list: ```bash export X509_TRUST_LIST_SOURCE_ENDPOINT="https://ec.europa.eu/tools/lotl/eu-lotl.xml" export X509_TRUST_LIST_SOURCE_CATEGORY=LoTL export X509_TRUST_LIST_SOURCE_SIGNING_CERTIFICATE="MIICxzCCAa+gAwIBAgI..." ``` When `X509_TRUST_LIST_SOURCE_ENDPOINT` is set and no structured `trust_list_sources` are configured, the connector assembles a single source from these flat fields. The category defaults to `LoTL` if omitted. **Field descriptions:** | Field | Type | Required | Description | | ---------------------- | ---------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------ | | `category` | string | Yes | Trust list category (see valid values below) | | `endpoint` | string (URL) | Yes | HTTPS URL of the trust list to fetch | | `signing_certificates` | array of strings | Yes | Base64-encoded DER certificates used to verify the list's signature | | `refresh_interval` | duration | No | How often to refresh this source (overrides global `X509_TRUST_STORE_REFRESH_INTERVAL`) | | `cache_ttl` | duration | No | Staleness window for this source (overrides global `X509_STALENESS_WINDOW`) | | `fallback_mode` | string | No | Behavior when fetch fails and cache exceeds staleness: `fail_closed`, `cached_trust`, `cached_trust_with_warning`. Default: `fail_closed`. | | `max_response_bytes` | int64 | No | Maximum response size for this source (overrides global `X509_MAX_RESPONSE_BYTES`) | **Valid category values:** | Category | Description | Verification path | | ---------------------- | ---------------------------------- | -------------------------------------------------------------------- | | `LoTL` | The EU List of Trusted Lists | Root of the hierarchy—points to Member State lists | | `PID_PROVIDER_LOTE` | PID Provider LoTE | PID credential verification | | `NATIONAL_TL` | Member State national Trusted List | QEAA, PuB-EAA, and voluntary non-qualified EAA verification | | `WALLET_PROVIDER_LOTE` | Wallet Provider LoTE | WIA/WUA verification | | `RULEBOOK_TL` | Rulebook-governed list | Accepted for configuration but not consulted during trust resolution | ##### Example configuration[​](#example-configuration "Direct link to Example configuration") ```bash export X509_TRUST_RESOLUTION_MODE=lotl export X509_TRUST_STORE_REFRESH_INTERVAL=6h export X509_STALENESS_WINDOW=24h export X509_LOTL_FETCH_TIMEOUT=30s export X509_MAX_RESPONSE_BYTES=10485760 ``` Restart the connector after setting these variables. #### Trust verification policy[​](#trust-verification-policy "Direct link to Trust verification policy") The trust verification policy controls how trust outcomes affect the callback per credential category. Configure a policy for each credential category independently. ##### Configuration[​](#configuration "Direct link to Configuration") | Variable | Type | Default | Description | | ------------------------------- | ------ | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `X509_TRUST_POLICY_SET` | string | `default-evaluate` | Named policy set baseline. The default set evaluates every category without enforcing. | | `X509_TRUST_POLICY_BY_CATEGORY` | map | (none) | Per-category policy overrides. Each key is a credential category (`PID`, `QEAA`, `PUB_EAA`, `NON_QUALIFIED_EAA`), each value is a policy (`enforce`, `evaluate`, `disabled`). | Example—enforce trust for PID credentials: ```bash export X509_TRUST_POLICY_BY_CATEGORY='{"PID":"enforce"}' ``` warning Setting a category to `enforce` requires `X509_TRUST_RESOLUTION_MODE=lotl` and a configured trust list source that can resolve that category. The connector rejects the configuration at startup if these requirements are not met. ##### Policy values[​](#policy-values "Direct link to Policy values") | Policy | Effect on callback | When to use | | -------------------- | -------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- | | `evaluate` (default) | Trust outcomes reported as fields on `FULFILLED` payloads. Flow completes regardless of trust verdict. | Production default—your backend applies appropriate legal weight. | | `enforce` | Trust failure for this category produces `VERIFICATION_FAILED` callback status. Credential is never delivered. | High-assurance deployments where untrusted credentials must be blocked before reaching your backend. | | `disabled` | Trust fields omitted entirely for this category. | Testing or when trust verification is not relevant for certain credential types. | ##### Policy × trust outcome → callback behavior[​](#policy--trust-outcome--callback-behavior "Direct link to Policy × trust outcome → callback behavior") | Trust outcome | `evaluate` | `enforce` | `disabled` | | ------------------ | ---------------------------------------------------------- | ------------------------------------------------------------- | -------------------------------- | | Issuer trusted | `FULFILLED` with `isTrusted: true` + enriched fields | `FULFILLED` with `isTrusted: true` + enriched fields | `FULFILLED` without trust fields | | Issuer not trusted | `FULFILLED` with `isTrusted: false` + `trustFailureReason` | `VERIFICATION_FAILED` | `FULFILLED` without trust fields | | Trust data stale | `FULFILLED` with `staleTrustData` present | `FULFILLED` with `staleTrustData` present (stale ≠ untrusted) | `FULFILLED` without trust fields | #### Interpret trust verification results[​](#interpret-trust-verification-results "Direct link to Interpret trust verification results") When the connector runs in LoTL-enabled mode with trust verification policy `evaluate` (the default), trust outcomes arrive as fields on `FULFILLED` callback payloads. This section explains what each `trustFailureReason` value means so you can make informed downstream decisions. | Failure reason | Meaning | Conditions | | ------------------------ | ----------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- | | `issuer_not_found` | The issuer's certificate does not match any entry on any trust list in the LoTL hierarchy. | The issuer may not be registered, may use a certificate not yet published, or may operate outside the EU trust framework. | | `issuer_withdrawn` | The issuer was found on a trust list but the entry's status is "withdrawn." | The member state's supervisory body has revoked the issuer's authorization. | | `issuer_suspended` | The issuer was found on a trust list but the entry's status is "suspended." | The member state's supervisory body has temporarily suspended the issuer's authorization. | | `trust_list_unavailable` | The trust list that should contain the issuer's entry could not be fetched and no valid cached copy is available. | Network failure, endpoint down, or staleness window exceeded for all applicable trust list sources. | This section does not prescribe specific customer actions—each failure reason represents a different risk profile, and the appropriate response depends on your business requirements and risk tolerance. #### What to expect in the callback[​](#what-to-expect-in-the-callback "Direct link to What to expect in the callback") When trust anchor verification is enabled in LoTL mode, the `FULFILLED` callback payload includes enriched trust fields: ```json { "status": "FULFILLED", "state": "abc123", "credentials": { "pid_identity": [ { "issuer": "https://pid-provider.example.de", "claims": { "given_name": "Erika", "family_name": "Mustermann", "birthdate": "1964-08-12" }, "signatureIsValid": true, "kbSignatureIsValid": true, "kbKeyId": "KrXxHnYsf-Inp0hW1M6r...", "validFrom": "2026-01-15T10:00:00Z", "validUntil": "2027-01-15T10:00:00Z", "supportRevocation": true, "isRevoked": false, "supportTrustAnchor": true, "isTrusted": true, "isCertificateRevoked": false, "credentialCategory": "PID", "trustSource": "lotl", "supervisoryMemberState": "DE", "qualifiedStatus": false, "trustDataTimestamp": "2026-05-15T08:30:00Z" } ] } } ``` **Field summary:** * `credentialCategory`—The credential's legal-effect classification (PID, QEAA, PUB\_EAA, NON\_QUALIFIED\_EAA) * `trustSource`—Where trust was resolved (`lotl`, `static`, `untrusted`) * `supervisoryMemberState`—ISO 3166-1 alpha-2 code of the supervisory Member State (present when `trustSource: "lotl"`) * `qualifiedStatus`—Whether the matched trust list entry is a qualified trust service (present when `trustSource: "lotl"`) * `trustDataTimestamp`—ISO 8601 timestamp of the trust data snapshot used for this verification * `trustFailureReason`—Present when `isTrusted: false` (see the preceding decision tree) * `staleTrustData`—Present when trust data is stale (object with `cachedFallback` and `pastNextUpdate` booleans) #### Static-only mode (fallback)[​](#static-only-mode-fallback "Direct link to Static-only mode (fallback)") For environments without LoTL infrastructure, the connector resolves trust against manually configured trust anchor certificates. Manual provisioning only Trust anchors are configured statically via environment variables. You must obtain trust anchor certificates from your federation operator and update the configuration manually when they change. ##### Configuration[​](#configuration-1 "Direct link to Configuration") | Variable | Required | Default | Description | | -------------------------- | ------------------ | ------- | ---------------------------------------------------------------------------------- | | `X509_VERIFY_TRUST_ANCHOR` | Yes | `false` | Enable static trust anchor resolution and CRL checking. Set to `true` to activate. | | `X509_TRUST_ANCHORS` | Yes (when enabled) | `""` | Comma-separated base64-encoded DER trust anchor certificates. | | `X509_CRL_TIMEOUT_SECONDS` | No | `10` | HTTP timeout in seconds for CRL fetch requests. | ##### Obtain trust anchor certificates[​](#obtain-trust-anchor-certificates "Direct link to Obtain trust anchor certificates") Contact your federation operator to obtain the trust anchor certificates for the credential issuers you want to verify. In the EUDI ecosystem, these are typically root CA certificates or federation trust anchor certificates published in a List of Trusted Entities (LoTE). Your federation operator should be able to provide them as PEM or DER files. If your federation does not yet distribute trust anchor certificates, you cannot use this feature. ##### Encode the certificates[​](#encode-the-certificates "Direct link to Encode the certificates") The connector's `X509_TRUST_ANCHORS` variable expects certificates in base64-encoded DER format. DER is the binary encoding of an X.509 certificate—as opposed to PEM, which is the same data wrapped in `-----BEGIN CERTIFICATE-----` / `-----END CERTIFICATE-----` headers and base64-encoded for text transport. You need to strip the PEM headers and re-encode the raw binary as a single base64 string with no line breaks. If your certificate is already in DER format (a `.der` or `.cer` file), skip the first part of the command: ```bash # From PEM: convert to DER, then base64-encode (no line breaks) openssl x509 -in trust-anchor.pem -outform DER | base64 | tr -d '\n' # From DER: base64-encode directly base64 -i trust-anchor.der | tr -d '\n' ``` The output is a single line of base64 characters with no whitespace. That is the value you set in `X509_TRUST_ANCHORS`. If you have multiple trust anchors, encode each certificate separately and join the values with commas: ```text , ``` ##### Configure the connector[​](#configure-the-connector "Direct link to Configure the connector") Example configuration: ```bash export X509_VERIFY_TRUST_ANCHOR=true export X509_TRUST_ANCHORS="," export X509_CRL_TIMEOUT_SECONDS=10 ``` Restart the connector after setting these variables. #### Testing[​](#testing "Direct link to Testing") ##### LoTL-enabled mode test checklist[​](#lotl-enabled-mode-test-checklist "Direct link to LoTL-enabled mode test checklist") * \[ ] `X509_TRUST_RESOLUTION_MODE=lotl` is set and the connector restarts without errors * A credential with an `x5c` chain from a LoTL-registered issuer returns `isTrusted: true` with `trustSource: "lotl"` * A credential from an unregistered issuer returns `isTrusted: false` with `trustFailureReason: "issuer_not_found"` * \[ ] `credentialCategory` is populated with the correct category for the presented credential * \[ ] `supervisoryMemberState` contains the ISO 3166-1 alpha-2 code of the issuer's member state * Trust verification policy `enforce` correctly produces `VERIFICATION_FAILED` for untrusted credentials ##### Static-only mode test checklist[​](#static-only-mode-test-checklist "Direct link to Static-only mode test checklist") You can only confirm static mode is working by presenting a real credential that includes an `x5c` certificate chain from an issuer whose trust anchor you have configured. The connector's test wallet does not produce credentials with `x5c` chains, so you cannot verify this feature in isolation using the standard development setup. When a credential with a valid `x5c` chain is presented and trust anchor verification is enabled, verify: * `supportTrustAnchor: true`—the credential was signed with an `x5c` certificate chain * `isTrusted: true`—the chain terminated at a configured trust anchor and the last certificate's signature was verified * `isCertificateRevoked: false`—no certificate in the chain was found on a CRL If `X509_VERIFY_TRUST_ANCHOR` is `false` (the default), `isTrusted` and `isCertificateRevoked` are both `false` even when `supportTrustAnchor` is `true`. The fields are present but trust and revocation checking was skipped. #### Troubleshooting[​](#troubleshooting "Direct link to Troubleshooting") ##### Trust resolution mode misconfiguration[​](#trust-resolution-mode-misconfiguration "Direct link to Trust resolution mode misconfiguration") `X509_TRUST_RESOLUTION_MODE` must be exactly `lotl` or `static`. Any other value prevents the connector from starting. Check for trailing whitespace or incorrect casing. ##### LoTL fetch failures on startup[​](#lotl-fetch-failures-on-startup "Direct link to LoTL fetch failures on startup") If the connector cannot fetch the LoTL on startup, it delays readiness until the fetch succeeds or the configured timeout is exceeded. Check network connectivity from the connector to the configured trust list source endpoints. ##### Staleness window exceeded (fail-closed)[​](#staleness-window-exceeded-fail-closed "Direct link to Staleness window exceeded (fail-closed)") When cached trust data exceeds the `X509_STALENESS_WINDOW` and a fresh fetch fails, the connector fails closed—`isTrusted` is `false` with `trustFailureReason: "trust_list_unavailable"`. Investigate why the trust list endpoint is unreachable and consider increasing the staleness window for unstable network environments. ##### issuer\_not\_found when issuer is expected to be on a trust list[​](#issuer_not_found-when-issuer-is-expected-to-be-on-a-trust-list "Direct link to issuer_not_found when issuer is expected to be on a trust list") Verify that the issuer's certificate is published on the correct trust list for the credential category. Check that the `X509_TRUST_LIST_SOURCES` configuration includes the appropriate source (for example, `PID_PROVIDER_LOTE` for PID credentials). ##### trust\_list\_unavailable when the list cannot be fetched[​](#trust_list_unavailable-when-the-list-cannot-be-fetched "Direct link to trust_list_unavailable when the list cannot be fetched") The connector could not fetch the trust list and the cached copy (if any) exceeded the staleness window. Check network connectivity, DNS resolution, and firewall rules from the connector to the trust list endpoint. Increase `X509_LOTL_FETCH_TIMEOUT` if the endpoint is slow. ##### Unexpected VERIFICATION\_FAILED when trust policy is set to enforce[​](#unexpected-verification_failed-when-trust-policy-is-set-to-enforce "Direct link to Unexpected VERIFICATION_FAILED when trust policy is set to enforce") When trust verification policy is `enforce` for a credential category, any trust failure for that category produces `VERIFICATION_FAILED`—even `trust_list_unavailable`. If this is too aggressive, switch to `evaluate` mode and handle trust failures in your backend logic. ##### isTrusted: false—trust anchor not matching (static mode)[​](#istrusted-falsetrust-anchor-not-matching-static-mode "Direct link to isTrusted: false—trust anchor not matching (static mode)") The chain's last certificate did not match any configured trust anchor. The connector first tries Authority Key Identifier (AKI) to Subject Key Identifier (SKI) matching, then falls back to Issuer Distinguished Name matching with signature verification. Verify that the correct trust anchor certificate is encoded in `X509_TRUST_ANCHORS`. Check that the certificate is in DER format before base64-encoding—encoding a PEM file directly (without the `openssl x509 -outform DER` conversion step) produces an invalid value. ##### CRL fetch timeout (static mode)[​](#crl-fetch-timeout-static-mode "Direct link to CRL fetch timeout (static mode)") The connector could not fetch the CRL within the configured timeout. When a CRL fetch fails, the connector logs a warning and tries the next CRL Distribution Point listed in the certificate. If no valid CRL can be obtained from any distribution point, the certificate is treated as not revoked (fail-open for CRL specifically). Trust anchor resolution itself is fail-closed: if the chain does not end at a configured trust anchor, `isTrusted` is `false`. Increase `X509_CRL_TIMEOUT_SECONDS` if CRL endpoints are slow, or check network connectivity from the connector to the CRL distribution point URLs. ##### Self-signed certificates in the chain (static mode)[​](#self-signed-certificates-in-the-chain-static-mode "Direct link to Self-signed certificates in the chain (static mode)") Self-signed certificates must not appear in the `x5c` chain. The trust anchor (root CA) is not included in the chain—it is configured separately via `X509_TRUST_ANCHORS`. If you see trust failures, verify the issuer is not including the root CA in the `x5c` header. #### Next steps[​](#next-steps "Direct link to Next steps") * [Get ready for production](/eudiw-connector/how-to-guides/going-to-production.md)—production readiness checklist * [Handle verification errors](/eudiw-connector/how-to-guides/error-handling.md)—handle `VERIFICATION_FAILED` when chain validation fails #### Further reading[​](#further-reading "Direct link to Further reading") * [LoTL trust verification](/eudiw-connector/explanations/trust-revocation/lotl-verification.md)—conceptual explanation of how LoTL verification works * [Callback events](/eudiw-connector/reference/callback-events.md)—full credential object field reference * [Revocation mechanisms](/eudiw-connector/explanations/trust-revocation/revocation-mechanisms.md)—how CRL checking works conceptually * [Certificates in EUDI](/eudiw-connector/explanations/trust-revocation/certificates.md)—X.509 certificate types and trust establishment --- ### Issue a credential This guide shows you how to issue a credential of any type using the Truvity EUDIW Connector [management API](/eudiw-connector/explanations/architecture/connector-architecture.md). You create a credential offer, display it to the user, and process the issuance callback in your backend. The examples use generic claim names. Substitute your own `credential_configuration_id` and `claims` for your use case. Prerequisites * Completed the [issuance quickstart](/eudiw-connector/getting-started/issue-credentials.md) #### Overview[​](#overview "Direct link to Overview") Create a credential offer via the management API, display the offer URI to the user as a QR code or deep link, and handle the issuance callback when the flow completes. **Time to implement**: 1–2 hours. #### Step 1: Create a credential offer[​](#step-1-create-a-credential-offer "Direct link to Step 1: Create a credential offer") Call `POST /offers` on the management API with the credential configuration ID and claims for the credential you want to issue. The connector returns `201 Created` on success. note The `credential_configuration_id`, claim names, and claim values in this guide are generic examples. In production, use the credential configuration ID and claims defined in your [Type Metadata](/eudiw-connector/how-to-guides/credential-type-configuration.md). * cURL ```bash curl -X POST http://connector:8081/offers \ -H "Content-Type: application/json" \ -d '{ "credential_configuration_id": "IdentityCredential", "claims": { "given_name": "Erika", "family_name": "Mustermann", "document_number": "T22000129", "issuing_country": "DE" } }' ``` Example response (`201 Created`): ```json { "offer_id": "abc123def456", "credential_offer_uri": "openid-credential-offer://?credential_offer_uri=https%3A%2F%2Fissuer.example.com%2Foidc4vci%2Foffers%2Fabc123def456" } ``` The request body contains: * `credential_configuration_id`—references a credential configuration in the connector's [Credential Issuer Metadata](/eudiw-connector/explanations/standards/oid4vci-protocol.md). Must match a configured type in your [Type Metadata](/eudiw-connector/how-to-guides/credential-type-configuration.md). * `claims`—the credential claims as key-value pairs. Use the claim names defined in your Type Metadata. * `tx_code` (optional)—adds transaction code authorization. Contains `input_mode` (`"numeric"` or `"text"`), `length` (number of characters), and an optional `description` (human-readable purpose displayed by wallets). See [Use transaction codes](/eudiw-connector/how-to-guides/tx-code.md) for details. The response contains: * `offer_id`—a correlation token for matching callbacks to this offer. Store this value in your session or database to identify which offer a callback belongs to. * `credential_offer_uri`—an `openid-credential-offer://` URI for the wallet. Display this to the user as a QR code or deep link. * `tx_code_value` (conditional)—present only when `tx_code` is included in the request. Deliver this to the user via a separate channel (for example, SMS or email). #### Step 2: Display the credential offer to the user[​](#step-2-display-the-credential-offer-to-the-user "Direct link to Step 2: Display the credential offer to the user") Use `credential_offer_uri` to generate a QR code when the user is on a desktop. Use it as a deep link when the user is on a mobile device. This step is client-side. Use any QR code library to encode the `credential_offer_uri` into a QR code image. For same-device flows, redirect the user's browser to the `credential_offer_uri` deep link. * Shell ```bash # Cross-device: generate a QR code PNG from the URI (requires qrencode) qrencode -o qrcode.png "$credential_offer_uri" # Same-device: open the deep link directly (macOS) open "$credential_offer_uri" ``` #### Step 3: Handle the issuance callback[​](#step-3-handle-the-issuance-callback "Direct link to Step 3: Handle the issuance callback") Implement a callback endpoint that receives the issuance event from the connector. The `offerId` field correlates the event with your original offer. Use it to look up the session you stored in Step 1. * cURL ```bash # Simulate an ISSUED callback for testing curl -X POST http://backend.example.com:3000/callback/issuance \ -H "Content-Type: application/json" \ -d '{ "eventId": "abc123def456", "status": "ISSUED", "offerId": "abc123def456" }' ``` The callback payload contains: | Field | Description | | -------------- | -------------------------------------------------------------------------------------------------------------------------------------- | | `eventId` | Correlation key tied to the offer lifecycle. Set to the same value as `offerId`. To deduplicate retries, combine `eventId` + `status`. | | `status` | One of `OFFER_CREATED`, `ISSUED`, `FAILED`, or `EXPIRED`. | | `offerId` | Correlation token matching the `offer_id` from Step 1. | | `errorDetails` | Present for `FAILED` status. Describes the failure reason. | Handle each status: * **OFFER\_CREATED**—the offer was created and the session is active. Use for audit logging or to start a timeout timer. * **ISSUED**—the credential was successfully issued to the wallet. Update your records accordingly. * **FAILED**—issuance failed. Check `errorDetails` for the reason, log the error, and consider offering the user a retry. * **EXPIRED**—the session time-to-live (TTL) expired before the wallet completed the flow. Create a new offer if the user wants to try again. For the complete list of payload fields and status descriptions, see the [callback events reference](/eudiw-connector/reference/callback-events.md). #### Testing[​](#testing "Direct link to Testing") ##### Test checklist[​](#test-checklist "Direct link to Test checklist") * Credential offer creates successfully and returns HTTP `201 Created` * Response contains `offer_id` and `credential_offer_uri` * QR code renders from `credential_offer_uri` * Deep link opens the wallet on mobile * Callback receives `OFFER_CREATED` status immediately after offer creation * Callback receives the issuance event with `ISSUED` status after wallet completes * Callback correctly correlates `offerId` with the original session * Callback handles all four statuses (`OFFER_CREATED`, `ISSUED`, `FAILED`, `EXPIRED`) * \[ ] `FAILED` callback includes `errorDetails` * Expired sessions are handled gracefully * \[ ] `eventId` matches `offerId` in all callbacks #### Troubleshooting[​](#troubleshooting "Direct link to Troubleshooting") ##### `unknown_credential_configuration` error[​](#unknown_credential_configuration-error "Direct link to unknown_credential_configuration-error") The `credential_configuration_id` in your offer request doesn't match any configured credential type. Verify that your [Type Metadata is configured](/eudiw-connector/how-to-guides/credential-type-configuration.md) and that the `credential_configuration_id` matches a key in the connector's Credential Issuer Metadata. ##### Callback not receiving events[​](#callback-not-receiving-events "Direct link to Callback not receiving events") The connector delivers callbacks asynchronously. Verify that your callback endpoint is reachable from the connector over internal networking. ##### Offer expired before wallet completes[​](#offer-expired-before-wallet-completes "Direct link to Offer expired before wallet completes") The default session time-to-live (TTL) is five minutes. If users consistently time out, consider adjusting the TTL or guiding users to scan the QR code promptly. #### Next steps[​](#next-steps "Direct link to Next steps") * [Implement AOC issuance](/eudiw-connector/how-to-guides/integration-scenarios/aoc-issuance.md)—production-ready Account Ownership Credential issuance in a banking app * [Use transaction codes](/eudiw-connector/how-to-guides/tx-code.md)—add transaction code authorization to issuance flows #### Further reading[​](#further-reading "Direct link to Further reading") * [OID4VCI protocol](/eudiw-connector/explanations/standards/oid4vci-protocol.md)—how the issuance protocol works * [Callback events](/eudiw-connector/reference/callback-events.md)—issuance event statuses and payload fields * [Error codes](/eudiw-connector/reference/error-codes.md)—wallet-facing HTTP error responses * [Configure credential types](/eudiw-connector/how-to-guides/credential-type-configuration.md)—set up Type Metadata for your credential types --- ### Configure credential types This guide shows you how to configure Type Metadata for the Truvity EUDIW Connector. Type Metadata defines the credential types your connector can issue—including claim definitions, selective disclosure settings, display metadata, and the Verifiable Credential Type (VCT) URI that wallets use to identify the credential type. Prerequisites * Completed the [verification quickstart](/eudiw-connector/getting-started/verify-credentials.md) * Access to the connector's configuration files #### Overview[​](#overview "Direct link to Overview") Type Metadata is a JSON document that describes a credential type. It tells the connector which claims to include in a credential and what display information to present to wallets. The connector loads Type Metadata from its configuration at startup and serves it at a public endpoint (`/oidc4vci/types/{credential_configuration_id}`) so wallets can discover supported credential types. Type Metadata feeds into the connector's [Credential Issuer Metadata](/eudiw-connector/explanations/standards/oid4vci-protocol.md)—the `credential_configurations_supported` map that wallets read from `GET /.well-known/openid-credential-issuer`. Each entry in that map corresponds to a configured credential configuration. When you create a credential offer, the `credential_configuration_id` must match a key in this map. **Time to implement**: 30 minutes. #### Step 1: Define Type Metadata[​](#step-1-define-type-metadata "Direct link to Step 1: Define Type Metadata") Create a Type Metadata JSON document for your credential type. The document follows the [SD-JWT VC](/eudiw-connector/explanations/credential-formats/sd-jwt.md) draft-13 §6.3 array-form schema. The example below defines an Account Ownership Credential (AOC) with bank account claims and selective disclosure settings. ```json { "vct": "https://issuer.example.com/oidc4vci/types/AccountOwnershipCredential", "display": [ { "lang": "en-US", "name": "Account Ownership Credential" } ], "claims": [ { "path": ["bankName"], "sd": "allowed", "display": [{ "lang": "en-US", "label": "Bank name" }] }, { "path": ["accountHolder"], "sd": "allowed", "display": [{ "lang": "en-US", "label": "Account holder" }] }, { "path": ["accountNumber"], "sd": "allowed", "display": [{ "lang": "en-US", "label": "Account number" }] }, { "path": ["iban"], "sd": "allowed", "display": [{ "lang": "en-US", "label": "IBAN" }] }, { "path": ["bic"], "sd": "allowed", "display": [{ "lang": "en-US", "label": "BIC" }] }, { "path": ["currency"], "sd": "allowed", "display": [{ "lang": "en-US", "label": "Currency" }] }, { "path": ["accountType"], "sd": "allowed", "display": [{ "lang": "en-US", "label": "Account type" }] } ] } ``` Key fields: * `vct`—a VCT URI placeholder. When `vct.source` is `local`, the connector rewrites this field to `{base_url}/oidc4vci/types/{credential_configuration_id}` at startup, making the Type Metadata available at a publicly resolvable URL. You can set any value here—the connector overrides it. * `display`—an array of localized display entries for the credential type. Each entry requires `lang` (a BCP47 language tag) and `name` (the display name wallets show for this credential). The connector uses this array in the Credential Issuer Metadata. * `claims`—an array of claim definitions. Each entry contains: * `path`—a JSON pointer array identifying the claim (for example, `["iban"]` for a top-level claim, or `["address", "street"]` for a nested claim). * `sd`—the selective disclosure policy: `"allowed"` (wallet holder can choose to disclose), `"always"` (always disclosed), or `"never"` (never selectively disclosable). * `display`—an array of localized display entries with `lang` and `label` that wallets show as the human-readable claim name. note When `vct.source` is `local`, the connector automatically generates the public VCT URL from its `base_url` and the credential configuration ID. You don't need to configure a separate VCT hosting endpoint. When `vct.source` is `external`, you provide the URL directly and are responsible for hosting the Type Metadata at that URL. For external sources, the connector injects a default `display` entry with `lang: "en-US"` and `name` set to the credential configuration ID if the `display` array is missing. #### Step 2: Load Type Metadata into the connector[​](#step-2-load-type-metadata-into-the-connector "Direct link to Step 2: Load Type Metadata into the connector") The connector loads Type Metadata from its configuration at startup. Each credential configuration references a Type Metadata JSON file via the `credential_configurations` configuration section. ```bash # Configure a credential type with a local Type Metadata file export CONNECTOR_CREDENTIAL_CONFIGURATIONS_ACCOUNTOWNERSHIPCREDENTIAL_VCT_SOURCE=local export CONNECTOR_CREDENTIAL_CONFIGURATIONS_ACCOUNTOWNERSHIPCREDENTIAL_VCT_FILEPATH=/config/type-metadata/aoc.json export CONNECTOR_CREDENTIAL_CONFIGURATIONS_ACCOUNTOWNERSHIPCREDENTIAL_SCOPE=aoc_credential ``` Each credential configuration requires: * `vct.source`—how the Type Metadata is loaded. Use `local` for a file on disk (the connector serves it at `{base_url}/oidc4vci/types/{config_id}`), or `external` for a URL that wallets resolve directly. * `vct.filepath`—path to the Type Metadata JSON file (required when `source` is `local`). * `vct.url`—the external VCT URL (required when `source` is `external`). You are responsible for hosting the Type Metadata at this URL. * `scope`—the OAuth 2.0 scope associated with this credential type. The credential configuration key (for example, `AccountOwnershipCredential` in `CONNECTOR_CREDENTIAL_CONFIGURATIONS_ACCOUNTOWNERSHIPCREDENTIAL_*`) becomes the `credential_configuration_id` you pass when creating offers. The environment variable uses an uppercase representation of the key, but the actual `credential_configuration_id` preserves the original casing. For Kubernetes deployments, store Type Metadata as a ConfigMap and mount it into the connector pod: ```yaml spec: containers: - name: connector env: - name: CONNECTOR_CREDENTIAL_CONFIGURATIONS_ACCOUNTOWNERSHIPCREDENTIAL_VCT_SOURCE value: local - name: CONNECTOR_CREDENTIAL_CONFIGURATIONS_ACCOUNTOWNERSHIPCREDENTIAL_VCT_FILEPATH value: /config/type-metadata/aoc.json - name: CONNECTOR_CREDENTIAL_CONFIGURATIONS_ACCOUNTOWNERSHIPCREDENTIAL_SCOPE value: aoc_credential volumeMounts: - name: type-metadata mountPath: /config/type-metadata/ readOnly: true volumes: - name: type-metadata configMap: name: connector-type-metadata ``` The connector serves the loaded Type Metadata at a public endpoint. Wallets discover available credential types through the Credential Issuer Metadata endpoint. #### Step 3: Verify the configuration[​](#step-3-verify-the-configuration "Direct link to Step 3: Verify the configuration") After starting the connector with your Type Metadata, verify that the credential type appears in the Credential Issuer Metadata. * cURL ```bash curl -s https://connector.example.com/.well-known/openid-credential-issuer | jq . ``` The response should include your credential type in the `credential_configurations_supported` map: ```json { "credential_issuer": "https://connector.example.com", "authorization_servers": ["https://auth.example.com"], "credential_endpoint": "https://connector.example.com/oidc4vci/credential", "nonce_endpoint": "https://connector.example.com/oidc4vci/nonce", "credential_configurations_supported": { "AccountOwnershipCredential": { "format": "dc+sd-jwt", "scope": "aoc_credential", "vct": "https://connector.example.com/oidc4vci/types/AccountOwnershipCredential", "cryptographic_binding_methods_supported": ["jwk"], "credential_signing_alg_values_supported": ["ES256"], "proof_types_supported": { "jwt": { "proof_signing_alg_values_supported": ["ES256"] } }, "credential_metadata": { "display": [ { "name": "Account Ownership Credential", "locale": "en-US" } ], "claims": [ { "path": ["bankName"], "display": [{ "name": "Bank name", "locale": "en-US" }] }, { "path": ["accountHolder"], "display": [{ "name": "Account holder", "locale": "en-US" }] }, { "path": ["accountNumber"], "display": [{ "name": "Account number", "locale": "en-US" }] }, { "path": ["iban"], "display": [{ "name": "IBAN", "locale": "en-US" }] }, { "path": ["bic"], "display": [{ "name": "BIC", "locale": "en-US" }] }, { "path": ["currency"], "display": [{ "name": "Currency", "locale": "en-US" }] }, { "path": ["accountType"], "display": [{ "name": "Account type", "locale": "en-US" }] } ] } } }, "signed_metadata": "" } ``` Confirm that: 1. Your credential configuration key (for example, `AccountOwnershipCredential`) appears as a key in `credential_configurations_supported`. 2. The `vct` value matches `{base_url}/oidc4vci/types/{credential_configuration_id}` (for local source) or your external URL. 3. The `credential_metadata.display` array reflects the `display` entries from your Type Metadata document. 4. The `credential_metadata.claims` array includes your configured claims with `path` arrays. 5. The `scope` field matches the scope you configured. #### Testing[​](#testing "Direct link to Testing") ##### Test checklist[​](#test-checklist "Direct link to Test checklist") * Credential Issuer Metadata endpoint (`GET /.well-known/openid-credential-issuer`) returns a response * \[ ] `credential_configurations_supported` contains your credential configuration key * The `vct` field is `{base_url}/oidc4vci/types/{credential_configuration_id}` (for local source) * The `format` field is `dc+sd-jwt` * The `scope` field matches your configured scope * \[ ] `credential_metadata.display` includes your credential type display entries with `name` and `locale` * \[ ] `credential_metadata.claims` includes your claims with `path` arrays * \[ ] `proof_types_supported` includes `jwt` with `ES256` * \[ ] `cryptographic_binding_methods_supported` includes `jwk` * The Type Metadata endpoint (`GET /oidc4vci/types/{credential_configuration_id}`) returns your JSON document with array-form `display` and `claims` * Creating a credential offer with the configured `credential_configuration_id` succeeds #### Troubleshooting[​](#troubleshooting "Direct link to Troubleshooting") ##### `unknown_credential_configuration` error when creating an offer[​](#unknown_credential_configuration-error-when-creating-an-offer "Direct link to unknown_credential_configuration-error-when-creating-an-offer") The `credential_configuration_id` in your offer request doesn't match any configured credential type. Verify that: 1. The credential configuration key in your environment variables matches the `credential_configuration_id` you use in the offer request (for example, `CONNECTOR_CREDENTIAL_CONFIGURATIONS_ACCOUNTOWNERSHIPCREDENTIAL_*` maps to `credential_configuration_id: "AccountOwnershipCredential"`). 2. The Type Metadata path in `CONNECTOR_CREDENTIAL_CONFIGURATIONS__VCT_FILEPATH` points to a valid JSON file. 3. The connector restarted after you added or modified credential configuration environment variables. ##### VCT URI not publicly resolvable[​](#vct-uri-not-publicly-resolvable "Direct link to VCT URI not publicly resolvable") Wallets fetch the `vct` URI to retrieve credential type metadata. When using `vct.source=local`, the connector serves the Type Metadata at `{base_url}/oidc4vci/types/{credential_configuration_id}`—ensure your `base_url` is publicly reachable. When using `vct.source=external`: 1. Verify the URI is accessible from the public internet (not just your internal network). 2. Check that the domain has valid DNS records and TLS certificates. 3. Ensure no firewall rules block external access to the URI. ##### Missing required fields in Type Metadata[​](#missing-required-fields-in-type-metadata "Direct link to Missing required fields in Type Metadata") The connector validates Type Metadata at startup. If the connector fails to start after adding a Type Metadata file, check the logs for validation errors. Common issues: * Missing or unreadable file—the path in `CONNECTOR_CREDENTIAL_CONFIGURATIONS__VCT_FILEPATH` must point to a valid JSON file. * Invalid JSON—the file must be valid JSON that can be parsed. * Missing `vct.source`—each credential configuration must specify either `local` or `external` as the source type. * Missing `vct.filepath`—required when `vct.source` is `local`. * Missing or empty `display` array—Type Metadata requires at least one display entry with `lang` and `name`. * Invalid `claims` format—`claims` must be an array of objects with `path` (non-empty array), `sd`, and optional `display`. The legacy object-keyed format is no longer accepted. #### Next steps[​](#next-steps "Direct link to Next steps") * [Issue a credential](/eudiw-connector/how-to-guides/credential-issuance.md)—use the configured credential type to issue credentials * [Build an AOC issuance flow](/eudiw-connector/tutorials/aoc-issuance-tutorial.md)—end-to-end tutorial using AOC Type Metadata #### Further reading[​](#further-reading "Direct link to Further reading") * [OID4VCI protocol](/eudiw-connector/explanations/standards/oid4vci-protocol.md)—how the issuance protocol uses credential type metadata * [Connector architecture](/eudiw-connector/explanations/architecture/connector-architecture.md)—system components and configuration model * [Manage certificates](/eudiw-connector/how-to-guides/certificates.md)—configure the Issuer Signing Certificate required for credential signing --- ### Verify a credential This guide shows you how to verify a credential of any type using the Truvity EUDIW Connector [management API](/eudiw-connector/explanations/architecture/connector-architecture.md). You create a presentation request, display it to the user, and process the verification callback in your backend. The examples use a generic [DCQL](/eudiw-connector/explanations/standards/dcql.md) query. Substitute your own DCQL query for your use case. Prerequisites * Completed the [verification quickstart](/eudiw-connector/getting-started/verify-credentials.md) #### Overview[​](#overview "Direct link to Overview") Create a presentation request via the management API, display the request URI to the user as a QR code or deep link, and handle the verification callback when the flow completes. **Time to implement**: 1–2 hours. #### Step 1: Create a presentation request[​](#step-1-create-a-presentation-request "Direct link to Step 1: Create a presentation request") Call `POST /oidc4vp` on the management API with a [DCQL](/eudiw-connector/explanations/standards/dcql.md) query specifying the credentials and attributes you need. note The VCT values, requested claims, and credential values in this guide are examples. In production, request the attributes required by your use case and available in the target [attestation scheme](/eudiw-connector/reference/glossary.md#eudi-wallet-ecosystem). Available attributes vary by issuer and member state. * cURL ```bash curl -X POST http://connector:8081/oidc4vp \ -H "Content-Type: application/json" \ -d '{ "dcql_query": { "credentials": [ { "id": "identity_credential", "format": "dc+sd-jwt", "meta": { "vct_values": ["urn:eudi:pid:1"] }, "claims": [ { "path": ["given_name"] }, { "path": ["family_name"] }, { "path": ["birthdate"] } ] } ] } }' ``` Example response: ```json { "state": "abc123", "same_device_request_uri": "openid4vp://?client_id=...&request_uri=https%3A%2F%2Fconnector.example.com%2Foidc4vp%2Fabc123%2Frequest%3Fflow_type%3Dsame-device", "cross_device_request_uri": "openid4vp://?client_id=...&request_uri=https%3A%2F%2Fconnector.example.com%2Foidc4vp%2Fabc123%2Frequest%3Fflow_type%3Dcross-device" } ``` Store the `state` value to correlate with the callback later. The request body contains: * `dcql_query`—a [DCQL query](/eudiw-connector/explanations/standards/dcql.md) specifying the credentials and claims you need. In this example, `dc+sd-jwt` specifies the [SD-JWT credential format](/eudiw-connector/explanations/credential-formats/sd-jwt.md) and `urn:eudi:pid:1` identifies the PID credential type. * `expires_in` (optional)—session TTL in seconds. Overrides the default (ten minutes). Omit to use the default. * `transaction_data` (optional)—an array of transaction data items to cryptographically bind to the request. See [Use transactional data](/eudiw-connector/how-to-guides/transactional-data.md) for details. * `redirect_uri` (optional)—a URI to redirect the user to after same-device flow. When provided, the `FULFILLED` callback includes a `responseCode` and the wallet response contains a `redirect_uri` with the code appended. Omit for cross-device flows. The response contains: * `state`—a correlation token to match the callback with this request. Store this value in your session or database. * `same_device_request_uri`—an `openid4vp://` URI for same-device flows. Pass the full URI to the wallet as a deep link. * `cross_device_request_uri`—an `openid4vp://` URI to render as a QR code for cross-device flows. #### Step 2: Display the request URI to the user[​](#step-2-display-the-request-uri-to-the-user "Direct link to Step 2: Display the request URI to the user") Use `cross_device_request_uri` to generate a QR code when the user is on a desktop. Use `same_device_request_uri` as a deep link when the user is on a mobile device. This step is client-side. Use any QR code library to encode the `cross_device_request_uri` into a QR code image. For same-device flows, redirect the user's browser to the `same_device_request_uri` deep link. * Shell ```bash # Cross-device: generate a QR code PNG from the URI (requires qrencode) qrencode -o qrcode.png "$cross_device_request_uri" # Same-device: open the deep link directly (macOS) open "$same_device_request_uri" ``` #### Step 3: Handle the verification callback[​](#step-3-handle-the-verification-callback "Direct link to Step 3: Handle the verification callback") Implement a callback endpoint that receives the `PresentedCredentialsEvent` from the connector. The `state` field correlates the event with your original request. Use it to look up the session you stored in Step 1. * cURL ```bash # Simulate a FULFILLED callback for testing curl -X POST https://example.com:3000/callback \ -H "Content-Type: application/json" \ -d '{ "status": "FULFILLED", "state": "abc123", "responseCode": "8k5CwzAseoGVK_bHQQJWMw", "credentials": { "identity_credential": [ { "issuer": "https://issuer.example.com", "claims": { "given_name": "Erika", "family_name": "Mustermann", "birthdate": "1964-08-12" }, "signatureIsValid": true, "supportRevocation": false, "supportTrustAnchor": true, "isTrusted": false, "isCertificateRevoked": false, "kbKeyId": "KrXxHnYsf-Inp0hW1M6r...", "kbSignatureIsValid": true } ] }, "credentialsRaw": { "identity_credential": [ { "claims": "eyJiaXJ0aGRhdGUiOiIx...", "issuer": "https://issuer.example.com", "kbKeyId": "KrXxHnYsf-Inp0hW1M6r..." } ] } }' ``` The `credentials` and `credentialsRaw` fields are absent for `REJECTED`, `EXPIRED`, `PROCESSING_ERROR`, and `VERIFICATION_FAILED` statuses. The `errorDetails` field is present for `REJECTED`, `PROCESSING_ERROR`, and `VERIFICATION_FAILED` statuses. For same-device `FULFILLED` callbacks, the event includes a `responseCode` field to correlate the browser redirect with the callback. Handle each status: * **FULFILLED**—the wallet presented credentials matching your DCQL query. Extract the verified claims from the `credentials` map. Evaluate the verification flags (`signatureIsValid`, `isTrusted`, `isCertificateRevoked`, `kbSignatureIsValid`) before accepting the credential—a `FULFILLED` status means the protocol completed, not that all trust checks passed. * **REJECTED**—the user declined the presentation request in their wallet. * **EXPIRED**—the session time-to-live (TTL) expired before the wallet responded. Create a new presentation request if the user wants to try again. * **PROCESSING\_ERROR**—the connector encountered an error processing the wallet's response. Check `errorDetails` for the reason. * **VERIFICATION\_FAILED**—the connector could not verify the presented credentials (for example, invalid signature, failed [key binding](/eudiw-connector/explanations/privacy-security/key-binding.md), unsatisfied DCQL requirements, or X.509 trust chain validation failure). Check `errorDetails` for the reason. For the complete list of statuses and payload fields, see the [callback events reference](/eudiw-connector/reference/callback-events.md). Data handling responsibility You are responsible for applying your own data retention and access control policies to credential data received through callbacks. The connector does not persist credential data after delivering the callback. #### Restrict accepted issuers with trusted\_authorities[​](#restrict-accepted-issuers-with-trusted_authorities "Direct link to Restrict accepted issuers with trusted_authorities") You can optionally restrict which issuers the connector accepts for a presentation request by adding a `trusted_authorities` constraint to your DCQL query. This uses the `etsi_tl` authority type from the OpenID4VP DCQL specification to narrow acceptance to issuers resolvable through the [LoTL/LoTE hierarchy](/eudiw-connector/explanations/trust-revocation/lotl-verification.md). For the `etsi_tl` type, each value must be an HTTPS URL identifying a trust list entry (for example, `https://eidas.ec.europa.eu/efda/tl-browser/api/v1/tl/EU`). When `trusted_authorities` is absent (the default), the connector accepts any issuer that resolves on the trust hierarchy—the trust verification result is reported on the callback payload for your backend to evaluate. When `trusted_authorities` is present, the connector only accepts credentials from issuers whose trust list entry matches one of the specified values. If the presented credential's issuer does not match, the verification fails before the callback is delivered. ##### Example DCQL query with trusted\_authorities[​](#example-dcql-query-with-trusted_authorities "Direct link to Example DCQL query with trusted_authorities") * cURL ```bash curl -X POST http://connector:8081/oidc4vp \ -H "Content-Type: application/json" \ -d '{ "dcql_query": { "credentials": [ { "id": "pid_identity", "format": "dc+sd-jwt", "meta": { "vct_values": ["urn:eudi:pid:1"] }, "claims": [ { "path": ["given_name"] }, { "path": ["family_name"] } ], "trusted_authorities": [ { "type": "etsi_tl", "values": ["https://eidas.ec.europa.eu/efda/tl-browser/api/v1/tl/EU"] } ] } ] } }' ``` The `trusted_authorities` constraint is per-credential in the DCQL query—you can apply different authority restrictions to different credential requests within the same presentation request. Trust verification results (credential category, trust source, supervisory member state) still appear on the callback payload regardless of whether `trusted_authorities` is used. See [Callback events](/eudiw-connector/reference/callback-events.md) for the full field reference. #### Testing[​](#testing "Direct link to Testing") ##### Test checklist[​](#test-checklist "Direct link to Test checklist") * Presentation request creates and returns `state`, `same_device_request_uri`, and `cross_device_request_uri` * QR code renders from `cross_device_request_uri` * Deep link opens the wallet on mobile * Callback receives the verification event with `FULFILLED` status * Callback correctly correlates `state` with the original session * Callback handles all five statuses (`FULFILLED`, `REJECTED`, `EXPIRED`, `PROCESSING_ERROR`, `VERIFICATION_FAILED`) * Same-device flow correctly uses `responseCode` for browser redirect correlation * Expired sessions are handled gracefully #### Troubleshooting[​](#troubleshooting "Direct link to Troubleshooting") ##### Callback not receiving events[​](#callback-not-receiving-events "Direct link to Callback not receiving events") The connector delivers callbacks synchronously. Verify that your callback endpoint is reachable from the connector and responds within the timeout. ##### Session correlation failures[​](#session-correlation-failures "Direct link to Session correlation failures") Verify that you store the `state` value from the `POST /oidc4vp` response and look it up when the callback arrives. The `state` value is a cryptographic random string generated by the connector. ##### Request expired before wallet responds[​](#request-expired-before-wallet-responds "Direct link to Request expired before wallet responds") The default session time-to-live (TTL) is ten minutes. If users consistently time out, consider adjusting the TTL via the `expires_in` request parameter or guiding users to scan the QR code promptly. #### Next steps[​](#next-steps "Direct link to Next steps") * [Implement KYC verification](/eudiw-connector/how-to-guides/integration-scenarios/kyc-verification.md)—verify customer identity using PID credentials * [Implement passwordless authentication](/eudiw-connector/how-to-guides/integration-scenarios/passwordless-authentication.md)—replace passwords with key binding proof #### Further reading[​](#further-reading "Direct link to Further reading") * [OID4VP protocol](/eudiw-connector/explanations/standards/oid4vp-protocol.md)—how the verification protocol works * [Callback events](/eudiw-connector/reference/callback-events.md)—Presented Credentials Event statuses and payload fields * [Error codes](/eudiw-connector/reference/error-codes.md)—wallet-facing HTTP error responses * [DCQL query language](/eudiw-connector/explanations/standards/dcql.md)—how to specify credential requirements --- ### Handle errors This guide shows you how to handle non-success callback statuses for both verification and issuance flows in your [callback](/eudiw-connector/explanations/architecture/connector-architecture.md) endpoint. You implement a handler that maps each error outcome to a user-facing message and add retry logic for recoverable errors. Prerequisites * Completed the [verification quickstart](/eudiw-connector/getting-started/verify-credentials.md) * Completed the [issuance quickstart](/eudiw-connector/getting-started/issue-credentials.md) #### Overview[​](#overview "Direct link to Overview") The connector delivers callback events to your endpoint at various points during verification and issuance flows—for example, when an issuance offer is created and when the flow completes. The [verification quickstart](/eudiw-connector/getting-started/verify-credentials.md#handle-the-callback) covers parsing verification events and extracting credentials from a `FULFILLED` response, and the [credential issuance guide](/eudiw-connector/how-to-guides/credential-issuance.md) covers handling the `ISSUED` status. This guide focuses on the non-success statuses for both flows. By default (trust verification policy `evaluate`), trust verification outcomes—trust failure reasons, staleness signals, and credential category determination—are reported as fields on `FULFILLED` payloads through the enriched trust fields, not through error statuses. When trust verification policy is set to `enforce` for a credential category, trust failure for that category produces `VERIFICATION_FAILED` status. See [Configure trust anchor verification](/eudiw-connector/how-to-guides/configure-trust-anchors.md) for trust verification policy configuration and how to interpret trust verification results. For the complete event schema including all payload fields, see the [callback events reference](/eudiw-connector/reference/callback-events.md). **Time to implement**: 30 minutes to 1 hour. #### Verification errors[​](#verification-errors "Direct link to Verification errors") The connector delivers a `PresentedCredentialsEvent` at the end of each presentation flow. The four non-success statuses are `REJECTED`, `EXPIRED`, `PROCESSING_ERROR`, and `VERIFICATION_FAILED`. ##### Step 1: Handle each error status[​](#step-1-handle-each-error-status "Direct link to Step 1: Handle each error status") Add a branch for each non-success status in your callback handler. The `credentials` and `credentialsRaw` fields are absent for all four statuses. The `errorDetails` field is present for `REJECTED`, `PROCESSING_ERROR`, and `VERIFICATION_FAILED`. | Status | What happened | `errorDetails` | Your response | Example user message | | --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ | --------------------------------- | -------------------------------------------------------------------------------------------------------- | | `REJECTED` | User declined the request in their wallet | Wallet's [OAuth 2.0](/eudiw-connector/reference/glossary.md#protocols-and-standards) error code (for example, `access_denied`) | Log error, offer retry | "You declined the verification request. Select 'Verify' to try again." | | `EXPIRED` | Session timed out before the wallet responded | Absent | Create new request | "Your verification session timed out. Select 'Verify' to start a new session." | | `PROCESSING_ERROR` | Internal failure (decryption, state validation, infrastructure) | Internal failure details | Log error, alert ops, offer retry | "Something went wrong during verification. Try again, and contact support if the problem persists." | | `VERIFICATION_FAILED` | Credential verification failed (invalid signature, [DCQL](/eudiw-connector/explanations/standards/dcql.md) query mismatch, or [transaction data](/eudiw-connector/how-to-guides/transactional-data.md) hash failure) | Verification failure details | Log error, deny access | "Your credential could not be verified. Contact your credential issuer if you believe this is an error." | * cURL ```bash # Simulate a REJECTED callback curl -X POST http://backend.example.com:3000/callback \ -H "Content-Type: application/json" \ -d '{"status": "REJECTED", "state": "abc123", "errorDetails": "access_denied"}' # Simulate an EXPIRED callback curl -X POST http://backend.example.com:3000/callback \ -H "Content-Type: application/json" \ -d '{"status": "EXPIRED", "state": "abc123"}' # Simulate a PROCESSING_ERROR callback curl -X POST http://backend.example.com:3000/callback \ -H "Content-Type: application/json" \ -d '{"status": "PROCESSING_ERROR", "state": "abc123", "errorDetails": "decryption_failed"}' # Simulate a VERIFICATION_FAILED callback curl -X POST http://backend.example.com:3000/callback \ -H "Content-Type: application/json" \ -d '{"status": "VERIFICATION_FAILED", "state": "abc123", "errorDetails": "invalid_signature"}' ``` ##### REJECTED[​](#rejected "Direct link to REJECTED") The user declined the presentation request in their wallet. Log the `errorDetails` field (which contains the wallet's [OAuth 2.0](/eudiw-connector/reference/glossary.md#protocols-and-standards) error code), inform the user, and offer to retry. **Example user message**: "You declined the verification request. Select 'Verify' to try again." ##### EXPIRED[​](#expired "Direct link to EXPIRED") The session timed out before the wallet responded. Create a new presentation request with a fresh `state` value. **Example user message**: "Your verification session timed out. Select 'Verify' to start a new session." ##### PROCESSING\_ERROR[​](#processing_error "Direct link to PROCESSING_ERROR") An internal processing failure occurred (for example, a decryption, state validation, or infrastructure error). Log the `errorDetails` field, alert your operations team, and offer the user a retry. **Example user message**: "Something went wrong during verification. Try again, and contact support if the problem persists." ##### VERIFICATION\_FAILED[​](#verification_failed "Direct link to VERIFICATION_FAILED") Credential verification failed. The `credentials` and `credentialsRaw` fields are absent. Use the `errorDetails` field to diagnose the specific failure. Do not grant access. This status occurs in all trust verification modes when the connector cannot verify the presented credentials. Common causes include: * **X.509 chain-internal failures**—an invalid cryptographic signature, an expired certificate, or a certificate extension violation. These indicate a technically invalid presentation, not an untrusted issuer. * **Presentation-level failures**—a [DCQL](/eudiw-connector/explanations/standards/dcql.md) query mismatch (the presented credential does not satisfy the request) or a [transaction data](/eudiw-connector/how-to-guides/transactional-data.md) hash failure (the wallet's signed hash does not match the expected value). Additionally, if the trust verification policy is set to `enforce` for a credential's category, trust anchor failures (issuer not found in the trust list, or a certificate revoked via CRL) also produce `VERIFICATION_FAILED`. By default (trust verification policy `evaluate`), trust anchor and Certificate Revocation List (CRL) outcomes do not produce `VERIFICATION_FAILED`—they are reported through the `isTrusted` and `isCertificateRevoked` fields on `FULFILLED` payloads when `supportTrustAnchor` is `true`. See [Revocation mechanisms](/eudiw-connector/explanations/trust-revocation/revocation-mechanisms.md) for background on how chain validation works and [Configure trust anchor verification](/eudiw-connector/how-to-guides/configure-trust-anchors.md) for trust verification policy configuration. **Example user message**: "Your credential could not be verified. Contact your credential issuer if you believe this is an error." ##### Step 2: Implement retry logic[​](#step-2-implement-retry-logic "Direct link to Step 2: Implement retry logic") When a recoverable error occurs (`REJECTED`, `EXPIRED`, or `PROCESSING_ERROR`), create a new presentation request with a fresh `state` value. Do not retry the same session—expired and rejected sessions cannot be reused. * cURL ```bash # Create a new presentation request to retry verification curl -X POST http://connector:8081/oidc4vp \ -H "Content-Type: application/json" \ -d '{ "dcql_query": { "credentials": [ { "id": "pid_identity", "format": "dc+sd-jwt", "meta": { "vct_values": ["urn:eudi:pid:1"] }, "claims": [ { "path": ["given_name"] }, { "path": ["family_name"] }, { "path": ["birthdate"] } ] } ] } }' ``` Example response: ```json { "state": "def456", "same_device_request_uri": "openid4vp://?client_id=...&request_uri=https%3A%2F%2Fconnector.example.com%2Foidc4vp%2Fdef456%2Frequest%3Fflow_type%3Dsame-device", "cross_device_request_uri": "openid4vp://?client_id=...&request_uri=https%3A%2F%2Fconnector.example.com%2Foidc4vp%2Fdef456%2Frequest%3Fflow_type%3Dcross-device" } ``` Store the new `state` value and display the new QR code or deep link to the user. ##### Understanding errorDetails[​](#understanding-errordetails "Direct link to Understanding errorDetails") The [OID4VP](/eudiw-connector/explanations/standards/oid4vp-protocol.md) specification defines error codes that wallets return when they cannot fulfill a presentation request. The connector maps these wallet-reported errors to the `REJECTED` status and includes the original error code in `errorDetails`. Log this field to diagnose integration issues at the protocol level. For the complete list of wallet-facing error codes, see the [error codes reference](/eudiw-connector/reference/error-codes.md). #### Issuance errors[​](#issuance-errors "Direct link to Issuance errors") The connector delivers issuance events to your callback endpoint at multiple points during each issuance flow. The [credential issuance guide](/eudiw-connector/how-to-guides/credential-issuance.md) covers handling the `ISSUED` status. This section focuses on the two non-success statuses: `FAILED` and `EXPIRED`. ##### Step 1: Handle each error status[​](#step-1-handle-each-error-status-1 "Direct link to Step 1: Handle each error status") Add a branch for each non-success status in your issuance callback handler. The `errorDetails` field is present for `FAILED`. | Status | What happened | `errorDetails` | Your response | Example user message | | --------- | ------------------------------------------------------------ | -------------- | --------------------------------- | ------------------------------------------------------------------------------------------------------------- | | `FAILED` | Issuance failed (issuer service unavailable, internal error) | Failure reason | Log error, alert ops, offer retry | "Something went wrong while issuing your credential. Try again, and contact support if the problem persists." | | `EXPIRED` | Session TTL expired before the wallet completed the flow | Absent | Create new credential offer | "Your issuance session timed out. Select 'Issue' to start a new session." | * cURL ```bash # Simulate a FAILED issuance callback curl -X POST http://backend.example.com:3000/callback \ -H "Content-Type: application/json" \ -d '{ "eventId": "abc123def456", "status": "FAILED", "offerId": "abc123def456", "errorDetails": "issuer service error: signing key validation failed" }' # Simulate an EXPIRED issuance callback curl -X POST http://backend.example.com:3000/callback \ -H "Content-Type: application/json" \ -d '{ "eventId": "abc123def456", "status": "EXPIRED", "offerId": "abc123def456" }' ``` ##### Step 2: Implement retry logic[​](#step-2-implement-retry-logic-1 "Direct link to Step 2: Implement retry logic") When a `FAILED` or `EXPIRED` callback occurs, create a new credential offer. Do not retry the same offer—expired and failed sessions cannot be reused. * cURL ```bash # Create a new credential offer to retry issuance (returns 201 Created) curl -X POST http://connector:8081/offers \ -H "Content-Type: application/json" \ -d '{ "credential_configuration_id": "IdentityCredential", "claims": { "given_name": "Erika", "family_name": "Mustermann", "document_number": "T22000129", "issuing_country": "DE" } }' ``` Example response (`201 Created`): ```json { "offer_id": "xyz789abc012", "credential_offer_uri": "openid-credential-offer://?credential_offer_uri=https%3A%2F%2Fissuer.example.com%2Foidc4vci%2Foffers%2Fxyz789abc012" } ``` Store the new `offer_id` and display the new `credential_offer_uri` as a QR code or deep link. ##### Understanding errorDetails[​](#understanding-errordetails-1 "Direct link to Understanding errorDetails") The `errorDetails` field in `FAILED` callbacks describes the infrastructure or processing failure. Log this field and alert your operations team. During the issuance protocol exchange, the connector and the authorization server also return standardized [OID4VCI](/eudiw-connector/explanations/standards/oid4vci-protocol.md) error codes directly to the wallet. These protocol-level errors are not delivered to your callback endpoint. For the complete list of wallet-facing issuance error codes, see the [error codes reference](/eudiw-connector/reference/error-codes.md). #### Testing[​](#testing "Direct link to Testing") ##### Test checklist[​](#test-checklist "Direct link to Test checklist") **Verification:** * Callback handler processes all four verification error statuses without errors * \[ ] `REJECTED` and `EXPIRED` statuses trigger retry flow with a new `state` * \[ ] `REJECTED`, `PROCESSING_ERROR`, and `VERIFICATION_FAILED` statuses log `errorDetails` * User-facing messages display for each status * \[ ] `VERIFICATION_FAILED` status denies access **Issuance:** * Callback handler processes `FAILED` and `EXPIRED` issuance statuses without errors * \[ ] `FAILED` status logs `errorDetails` * \[ ] `FAILED` and `EXPIRED` statuses trigger retry flow with a new credential offer * User-facing messages display for each status #### Troubleshooting[​](#troubleshooting "Direct link to Troubleshooting") ##### Callback receives unexpected status values[​](#callback-receives-unexpected-status-values "Direct link to Callback receives unexpected status values") The connector delivers exactly one of the documented statuses for each flow. If your handler receives an unrecognized value, log it and treat it as an error. Check that you are running a compatible connector version. ##### Wallet returns unsupported response mode or algorithm errors[​](#wallet-returns-unsupported-response-mode-or-algorithm-errors "Direct link to Wallet returns unsupported response mode or algorithm errors") The connector operates under the [HAIP profile](/eudiw-connector/explanations/standards/haip.md), which mandates the `direct_post.jwt` response mode and ES256 for signing. If the wallet does not support these requirements, it returns an error at the protocol level. Check that the wallet supports the HAIP profile. These errors typically appear as `REJECTED` callbacks with [OID4VP](/eudiw-connector/explanations/standards/oid4vp-protocol.md) error codes in the `errorDetails` field. ##### Retry creates duplicate sessions[​](#retry-creates-duplicate-sessions "Direct link to Retry creates duplicate sessions") Ensure you invalidate the old session before creating a new request or offer. Use the `state` value (verification) or `offer_id` (issuance) as the session key and overwrite it when retrying. #### Next steps[​](#next-steps "Direct link to Next steps") * [KYC verification](/eudiw-connector/how-to-guides/integration-scenarios/kyc-verification.md)—implement identity verification with full error handling * [AOC issuance](/eudiw-connector/how-to-guides/integration-scenarios/aoc-issuance.md)—implement credential issuance with full error handling * [Going to production](/eudiw-connector/how-to-guides/going-to-production.md)—production readiness checklist #### Further reading[​](#further-reading "Direct link to Further reading") * [Callback events](/eudiw-connector/reference/callback-events.md)—complete event status and payload reference * [Error codes](/eudiw-connector/reference/error-codes.md)—wallet-facing HTTP error responses * [OID4VCI protocol](/eudiw-connector/explanations/standards/oid4vci-protocol.md)—how the issuance protocol works * [HAIP profile](/eudiw-connector/explanations/standards/haip.md)—required algorithms, response modes, and credential formats * [Connector architecture](/eudiw-connector/explanations/architecture/connector-architecture.md)—how the connector processes requests and delivers results --- ### Get ready for production This guide provides a checklist for deploying the Truvity EUDIW Connector in a production environment. It covers technical configuration, security hardening, and compliance requirements for handling verified credential data. Prerequisites * Completed the [verification quickstart](/eudiw-connector/getting-started/verify-credentials.md) #### Technical checklist[​](#technical-checklist "Direct link to Technical checklist") * Obtain Relying Party (RP) registration from your member state Registrar * Acquire a CA-issued X.509 access certificate (see [Manage certificates](/eudiw-connector/how-to-guides/certificates.md)) Trust list prerequisite The access certificate must be issued by a Certificate Authority (CA) whose root is included in the member state's [List of Trusted Entities (LoTE)](/eudiw-connector/explanations/trust-revocation/trust-lists.md). RP registration and certificate issuance are linked through the trust infrastructure—the Registrar records your registration, and the Access CA issues a certificate that chains to a trusted root. * Configure the connector to load certificates from the file system (in Kubernetes, mount them as [secret volumes](/eudiw-connector/how-to-guides/certificates.md)) * Configure `base_url` to the public Ingress hostname * If verifying credentials with X.509 certificate chains, configure trust anchor verification—either LoTL-driven (recommended for production) or static-only (see [Configure trust anchor verification](/eudiw-connector/how-to-guides/configure-trust-anchors.md)) * Implement a [callback](/eudiw-connector/explanations/architecture/connector-architecture.md) endpoint that accepts POST requests, responds with a 2xx status within two seconds, and parses the `PresentedCredentialsEvent` JSON payload (see [callback events](/eudiw-connector/reference/callback-events.md)) * Test presentation flows with both same-device and cross-device patterns * Implement error handling for all non-success event statuses: `REJECTED`, `EXPIRED`, `PROCESSING_ERROR`, and `VERIFICATION_FAILED` (see [handle verification errors](/eudiw-connector/how-to-guides/error-handling.md)) #### Callback endpoint reliability[​](#callback-endpoint-reliability "Direct link to Callback endpoint reliability") The connector retries callback delivery with a default of one retry and a two-second timeout per attempt. If your callback endpoint is unavailable or responds too slowly, the connector returns a 503 or 500 error to the wallet, and the user sees a failure on their device. To avoid this: * Ensure your callback endpoint is highly available. * Respond within two seconds. Offload heavy processing to an asynchronous queue. * Monitor callback endpoint latency and error rates. #### Security checklist[​](#security-checklist "Direct link to Security checklist") * Isolate the public protocol port (8080) from the internal management API port (8081) at the network level so that management API traffic is not reachable from the internet (for example, using [network policies](/eudiw-connector/explanations/architecture/connector-architecture.md) in Kubernetes or firewall rules in other environments) * Enable TLS for the callback endpoint if it is not on the same internal network as the connector * Establish certificate rotation procedures and monitor expiration dates * Ensure the callback endpoint responds within the connector's timeout (default two seconds per attempt) to avoid wallet-facing errors * Conduct a security review of your credential handling code #### Compliance checklist[​](#compliance-checklist "Direct link to Compliance checklist") * Define a data retention policy for credential data received through callbacks, specifying how long you store both the `credentials` (verified data) and `credentialsRaw` (raw credential data) fields before deletion * Implement access controls limiting which internal systems can read stored credential data * Provide a privacy notice to end users explaining what credential data you collect, why you collect it, and how long you retain it * Document your lawful basis for processing verified credential data under [GDPR](https://commission.europa.eu/law/law-topic/data-protection_en) (for example, contractual necessity or legitimate interest) * Implement data subject rights procedures so individuals can request access to, erasure of, or portability of their credential data * Establish logging and audit trails for compliance reporting #### Further reading[​](#further-reading "Direct link to Further reading") * [Manage certificates](/eudiw-connector/how-to-guides/certificates.md)—generate test certificates and configure production certificates * [Callback events](/eudiw-connector/reference/callback-events.md)—Presented Credentials Event statuses and payload fields * [Error codes](/eudiw-connector/reference/error-codes.md)—wallet-facing HTTP error responses * [Connector architecture](/eudiw-connector/explanations/architecture/connector-architecture.md)—system components, data flow, and security model --- ### Implement AOC issuance This guide shows you how to issue an Account Ownership Credential (AOC) to an [EUDI Wallet](/eudiw-connector/overview/what-is-eudiw-connector.md) as part of a bank account opening flow. You create a credential offer with AOC-specific claims derived from the customer's account session, display a QR code or deep link, and process the issuance [callback](/eudiw-connector/explanations/architecture/connector-architecture.md) to update the account status. For a step-by-step learning experience that builds a complete project from scratch, see the [AOC issuance tutorial](/eudiw-connector/tutorials/aoc-issuance-tutorial.md). For a conceptual overview, see [AOC issuance use case](/eudiw-connector/explanations/use-cases/aoc-issuance.md). Prerequisites * Completed the [issuance quickstart](/eudiw-connector/getting-started/issue-credentials.md) * Familiarity with [credential issuance](/eudiw-connector/how-to-guides/credential-issuance.md) #### Overview[​](#overview "Direct link to Overview") You build a production-ready AOC issuance flow for a banking app. After a customer completes account opening and identity verification, your backend creates a credential offer with claims derived from the account session, displays the offer to the customer, and handles the callback to mark the account as credential-enabled. This guide differs from the [generic credential issuance how-to](/eudiw-connector/how-to-guides/credential-issuance.md) by covering production integration concerns specific to AOC: correlating offers to authenticated bank customers, deriving AOC claims from the account opening session, and handling the issuance callback to update account status. **Time to implement**: 2–4 hours. #### Step 1: Create an AOC credential offer[​](#step-1-create-an-aoc-credential-offer "Direct link to Step 1: Create an AOC credential offer") After the customer completes account opening and identity verification (KYC), create a credential offer using claims from the authenticated session. Call `POST /offers` on the management API with the AOC credential configuration ID and claims derived from the account opening session. The connector returns `201 Created` on success. Correlate the `offer_id` in the response with the authenticated bank customer so you can update the correct account when the callback arrives. * cURL ```bash curl -X POST http://connector:8081/offers \ -H "Content-Type: application/json" \ -d '{ "credential_configuration_id": "AccountOwnershipCredential", "claims": { "bankName": "Example Bank", "accountHolder": "Erika Mustermann", "accountNumber": "1234567890", "iban": "DE99370501981234567890", "bic": "COLSDE33XXX", "currency": "EUR", "accountType": "checking", "sub": "user-uuid-123", "userId": "user-uuid-123" } }' ``` Example response (`201 Created`): ```json { "offer_id": "abc123def456", "credential_offer_uri": "openid-credential-offer://?credential_offer_uri=https%3A%2F%2Fissuer.example.com%2Foidc4vci%2Foffers%2Fabc123def456" } ``` The request body contains: * `credential_configuration_id`—references the AOC credential configuration in the connector's [Credential Issuer Metadata](/eudiw-connector/explanations/standards/oid4vci-protocol.md). Must match a configured type in your [Type Metadata](/eudiw-connector/how-to-guides/credential-type-configuration.md). * `claims`—AOC-specific claims derived from the account opening session. These include `bankName`, `accountHolder`, `accountNumber`, `iban`, `bic`, `currency`, `accountType`, `sub`, and `userId`. * `tx_code` (optional)—adds transaction code authorization. See [Use transaction codes](/eudiw-connector/how-to-guides/tx-code.md) for details. The response contains: * `offer_id`—a correlation token for matching callbacks to this offer. Store this alongside the customer's account ID so you can update the correct account when the callback arrives. * `credential_offer_uri`—an `openid-credential-offer://` URI for the wallet. Display this to the customer as a QR code or deep link. * `tx_code_value` (conditional)—present only when `tx_code` is included in the request. Deliver this to the customer via a separate channel (for example, SMS or email). #### Step 2: Display the credential offer[​](#step-2-display-the-credential-offer "Direct link to Step 2: Display the credential offer") Present the `credential_offer_uri` to the customer after account opening completes. Use a QR code for cross-device flows (customer is on a desktop) or a deep link for same-device flows (customer is on a mobile device). * Shell ```bash # Cross-device: generate a QR code PNG from the URI (requires qrencode) qrencode -o qrcode.png "$credential_offer_uri" # Same-device: open the deep link directly (macOS) open "$credential_offer_uri" ``` #### Step 3: Implement the callback handler[​](#step-3-implement-the-callback-handler "Direct link to Step 3: Implement the callback handler") Implement a callback endpoint that receives the issuance event from the connector. Use the `offerId` field to look up the customer session you stored in Step 1 and update the account status based on the issuance outcome. * cURL ```bash # Simulate an ISSUED callback for testing curl -X POST https://example.com:3000/callback/issuance \ -H "Content-Type: application/json" \ -d '{ "eventId": "abc123def456", "status": "ISSUED", "offerId": "abc123def456" }' ``` The callback payload contains: | Field | Description | | -------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | | `eventId` | Correlation key tied to the offer lifecycle. Set to the same value as `offerId`. To deduplicate retries, combine `eventId` with `status`. | | `status` | One of `OFFER_CREATED`, `ISSUED`, `FAILED`, or `EXPIRED`. | | `offerId` | Correlation token matching the `offer_id` from Step 1. | | `errorDetails` | Present for `FAILED` status. Describes the failure reason. | Handle each status: * **OFFER\_CREATED**—the offer was created and the session is active. Use for audit logging or to start a timeout timer. * **ISSUED**—the AOC was successfully issued to the customer's wallet. Update the account status to reflect that the credential is active. The customer can now use the AOC for [passwordless authentication](/eudiw-connector/how-to-guides/integration-scenarios/passwordless-authentication.md). * **FAILED**—issuance failed. Check `errorDetails` for the reason, log the error, and consider offering the customer a retry from the account dashboard. * **EXPIRED**—the session time-to-live (TTL) expired before the wallet completed the flow. Create a new offer if the customer wants to try again. For the complete list of payload fields and status descriptions, see the [callback events reference](/eudiw-connector/reference/callback-events.md). #### Testing[​](#testing "Direct link to Testing") ##### Test checklist[​](#test-checklist "Direct link to Test checklist") * Credential offer creates with AOC-specific claims and returns `offer_id` and `credential_offer_uri` * Response status is HTTP `201 Created` * \[ ] `offer_id` is correctly correlated with the customer's account session * QR code renders from `credential_offer_uri` * Deep link opens the wallet on mobile * Callback receives `OFFER_CREATED` status immediately after offer creation * Callback receives the issuance event with `ISSUED` status after wallet completes * Callback correctly correlates `offerId` with the customer session and updates account status * Callback handles all four statuses (`OFFER_CREATED`, `ISSUED`, `FAILED`, `EXPIRED`) * \[ ] `FAILED` callback includes `errorDetails` and logs the failure * Expired sessions are handled gracefully with an option to retry * Account status reflects the issuance outcome (credential-enabled, failed, or expired) * \[ ] `eventId` matches `offerId` in all callbacks #### Troubleshooting[​](#troubleshooting "Direct link to Troubleshooting") ##### Session correlation failures[​](#session-correlation-failures "Direct link to Session correlation failures") Verify that you store the `offer_id` from the `POST /offers` response alongside the customer's account ID and look it up when the callback arrives. The `offerId` in the callback matches the `offer_id` from the original offer response. ##### Offer expiration before wallet completes[​](#offer-expiration-before-wallet-completes "Direct link to Offer expiration before wallet completes") The default session time-to-live (TTL) is five minutes. If customers consistently time out during account opening, consider creating the credential offer only after the customer confirms they are ready to scan, or guide them to scan the QR code promptly. ##### `unknown_credential_configuration` error[​](#unknown_credential_configuration-error "Direct link to unknown_credential_configuration-error") The `credential_configuration_id` in your offer request doesn't match any configured credential type. Verify that your [Type Metadata is configured](/eudiw-connector/how-to-guides/credential-type-configuration.md) for the AOC credential type and that the `credential_configuration_id` matches a key in the connector's Credential Issuer Metadata. #### Next steps[​](#next-steps "Direct link to Next steps") * [Issue a credential](/eudiw-connector/how-to-guides/credential-issuance.md)—underlying API mechanics for credential issuance * [Use transaction codes](/eudiw-connector/how-to-guides/tx-code.md)—add transaction code authorization to issuance flows * [Handle errors](/eudiw-connector/how-to-guides/error-handling.md)—build robust status handling for all issuance outcomes #### Further reading[​](#further-reading "Direct link to Further reading") * [AOC issuance use case](/eudiw-connector/explanations/use-cases/aoc-issuance.md)—conceptual overview of why banks issue AOCs * [OID4VCI protocol](/eudiw-connector/explanations/standards/oid4vci-protocol.md)—how the issuance protocol works * [Callback events](/eudiw-connector/reference/callback-events.md)—issuance event statuses and payload fields * [Passwordless authentication](/eudiw-connector/how-to-guides/integration-scenarios/passwordless-authentication.md)—use the issued AOC for login --- ### Implement KYC verification This guide shows you how to verify customer identity using Personal Identification Data ([PID](/eudiw-connector/reference/glossary.md#eudi-wallet-ecosystem)) credentials from an [EUDI Wallet](/eudiw-connector/overview/what-is-eudiw-connector.md). You create a presentation request for government-issued identity attributes, display a QR code or deep link, and process verified data in your [callback](/eudiw-connector/explanations/architecture/connector-architecture.md) endpoint. For a step-by-step learning experience that builds a complete project from scratch, see the [KYC verification tutorial](/eudiw-connector/tutorials/kyc-tutorial.md). Prerequisites * Completed the [verification quickstart](/eudiw-connector/getting-started/verify-credentials.md) #### Overview[​](#overview "Direct link to Overview") You request PID attributes (name, date of birth, address, nationalities) from an EUDI Wallet, verify them cryptographically, and deliver the result to your backend. This replaces document scans with government-issued digital credentials. **Time to implement**: 2–4 hours. #### Step 1: Create a presentation request[​](#step-1-create-a-presentation-request "Direct link to Step 1: Create a presentation request") Call `POST /oidc4vp` on the management API with a [DCQL](/eudiw-connector/explanations/standards/dcql.md) query requesting PID attributes for identity verification. note The VCT values, requested claims, and credential values in this guide are examples. In production, request the attributes required by your use case and available in the target [attestation scheme](/eudiw-connector/reference/glossary.md#eudi-wallet-ecosystem). Available attributes vary by issuer and member state. * cURL ```bash curl -X POST http://connector:8081/oidc4vp \ -H "Content-Type: application/json" \ -d '{ "dcql_query": { "credentials": [ { "id": "pid_kyc", "format": "dc+sd-jwt", "meta": { "vct_values": ["urn:eudi:pid:1"] }, "claims": [ { "path": ["given_name"] }, { "path": ["family_name"] }, { "path": ["birthdate"] }, { "path": ["address"] }, { "path": ["nationalities"] } ] } ] }, "expires_in": 600 }' ``` Example response: ```json { "state": "abc123", "same_device_request_uri": "openid4vp://?client_id=x509_hash%3Aabc123def456&request_uri=https%3A%2F%2Fconnector.example.com%2Foidc4vp%2Fabc123%2Frequest%3Fflow_type%3Dsame-device", "cross_device_request_uri": "openid4vp://?client_id=x509_hash%3Aabc123def456&request_uri=https%3A%2F%2Fconnector.example.com%2Foidc4vp%2Fabc123%2Frequest%3Fflow_type%3Dcross-device" } ``` Store the `state` value to correlate with the callback later. The response contains `state` for callback correlation, `cross_device_request_uri` for QR codes, and `same_device_request_uri` for deep links. Both URIs include a `client_id` derived from the connector's X.509 access certificate and a `flow_type` parameter (`same-device` or `cross-device`). In the DCQL query, `dc+sd-jwt` specifies the [SD-JWT credential format](/eudiw-connector/explanations/credential-formats/sd-jwt.md) and `urn:eudi:pid:1` identifies the PID credential type. The `expires_in` value is in seconds (600 = 10 minutes). #### Step 2: Display the QR code or deep link[​](#step-2-display-the-qr-code-or-deep-link "Direct link to Step 2: Display the QR code or deep link") Use `cross_device_request_uri` to generate a QR code when the user is on a desktop. Use `same_device_request_uri` as a deep link when the user is on a mobile device. This step is client-side. Use any QR code library (for example, `qrcode` for Node.js or `com.google.zxing` for Java) to encode the `cross_device_request_uri` into a QR code image. For same-device flows, redirect the user's browser to the `same_device_request_uri` deep link. * Shell ```bash # Cross-device: generate a QR code PNG from the URI (requires qrencode) qrencode -o qrcode.png "$cross_device_request_uri" # Same-device: open the deep link directly (macOS) open "$same_device_request_uri" ``` #### Step 3: Implement the callback handler[​](#step-3-implement-the-callback-handler "Direct link to Step 3: Implement the callback handler") Implement a callback endpoint that receives the `PresentedCredentialsEvent` from the connector. The `state` field correlates the event with your original request. For same-device flows, the `responseCode` field correlates the browser redirect with the callback. The `credentials` and `credentialsRaw` fields may be absent for `REJECTED`, `EXPIRED`, `PROCESSING_ERROR`, and `VERIFICATION_FAILED` statuses. The `errorDetails` field is present only for `REJECTED`, `PROCESSING_ERROR`, and `VERIFICATION_FAILED`. * cURL ```bash # Simulate a FULFILLED callback for testing curl -X POST http://localhost:3000/callback/kyc \ -H "Content-Type: application/json" \ -d '{ "status": "FULFILLED", "state": "abc123", "responseCode": "xyz789", "credentials": { "pid_kyc": [ { "issuer": "https://issuer.example.com", "claims": { "given_name": "Erika", "family_name": "Mustermann", "birthdate": "1964-08-12", "address": {"street_address": "Domplein 1", "house_number": "1", "postal_code": "90210", "country": "NL", "locality": "Utrecht", "region": "Utrecht"}, "nationalities": ["NL"] }, "signatureIsValid": true, "supportRevocation": false, "supportTrustAnchor": true, "isTrusted": false, "kbKeyId": "KrXxHnYsf-abc123", "kbSignatureIsValid": true } ] }, "credentialsRaw": { "pid_kyc": [ { "claims": "eyJ...", "issuer": "https://issuer.example.com", "kbKeyId": "KrXxHnYsf-abc123" } ] } }' ``` The `isRevoked` field is only present when `supportRevocation` is `true`, and `isTrusted` is only present when `supportTrustAnchor` is `true`. A missing `isRevoked` does not mean "not revoked"—it means revocation checking is not supported for this credential. Always check the `support*` flags before reading the dependent fields. The `kbKeyId` and `kbSignatureIsValid` fields are present when the credential includes [device binding](/eudiw-connector/explanations/privacy-security/key-binding.md). Use `kbKeyId` to recognize returning users across sessions. The `validFrom` and `validUntil` fields are present when the credential includes `iat` and `exp` claims. For the complete list of statuses and error codes, see the [callback events reference](/eudiw-connector/reference/callback-events.md). #### Testing[​](#testing "Direct link to Testing") ##### Test checklist[​](#test-checklist "Direct link to Test checklist") * Presentation request creates and returns `state`, `same_device_request_uri`, and `cross_device_request_uri` * QR code renders from `cross_device_request_uri` * Deep link redirects to the wallet on mobile * Callback receives `PresentedCredentialsEvent` with `FULFILLED` status * Callback correctly correlates `state` with the original session * Callback handles all five statuses (`FULFILLED`, `REJECTED`, `EXPIRED`, `PROCESSING_ERROR`, `VERIFICATION_FAILED`) * Same-device flow correctly uses `responseCode` for browser redirect correlation * Expired sessions are handled gracefully #### Troubleshooting[​](#troubleshooting "Direct link to Troubleshooting") ##### Callback not receiving events[​](#callback-not-receiving-events "Direct link to Callback not receiving events") The connector delivers callbacks synchronously with a default two-second timeout per attempt and one retry. Verify that your callback endpoint is reachable from the connector and responds within the timeout. ##### Missing credential fields[​](#missing-credential-fields "Direct link to Missing credential fields") The fields `isRevoked`, `isTrusted`, `kbKeyId`, `kbSignatureIsValid`, `validFrom`, and `validUntil` are optional. Always check the `support*` flags before reading the dependent fields. ##### Session correlation failures[​](#session-correlation-failures "Direct link to Session correlation failures") Verify that you store the `state` value from the `POST /oidc4vp` response and look it up when the callback arrives. The `state` value is a cryptographic random string generated by the connector. #### Next steps[​](#next-steps "Direct link to Next steps") * [Passwordless authentication](/eudiw-connector/how-to-guides/integration-scenarios/passwordless-authentication.md)—implement login with key binding proof * [Error handling](/eudiw-connector/how-to-guides/error-handling.md)—build robust status handling for all verification outcomes * [Going to production](/eudiw-connector/how-to-guides/going-to-production.md)—production readiness checklist #### Further reading[​](#further-reading "Direct link to Further reading") * [KYC use case explained](/eudiw-connector/explanations/use-cases/kyc.md)—conceptual overview of identity verification flows * [DCQL query language](/eudiw-connector/explanations/standards/dcql.md)—how to specify credential requirements * [Device binding](/eudiw-connector/explanations/privacy-security/key-binding.md)—how kbKeyId and device binding proof work * [Error codes](/eudiw-connector/reference/error-codes.md)—wallet-facing HTTP error responses * [Callback events](/eudiw-connector/reference/callback-events.md)—Presented Credentials Event statuses and payload fields --- ### Implement passwordless authentication This guide shows you how to implement passwordless authentication using [key binding](/eudiw-connector/explanations/privacy-security/key-binding.md) proof from an EUDI Wallet. You create a presentation request that enforces cryptographic holder binding, verify the proof in your [callback](/eudiw-connector/explanations/architecture/connector-architecture.md), and extract a stable user identifier to bind to sessions or accounts. For a step-by-step learning experience that builds a complete project from scratch, see the [passwordless authentication tutorial](/eudiw-connector/tutorials/auth-tutorial.md). For a conceptual overview, see [Authentication with EUDI Wallet](/eudiw-connector/explanations/use-cases/authentication.md). Prerequisites * Completed the [verification quickstart](/eudiw-connector/getting-started/verify-credentials.md) * A credential with [key binding](/eudiw-connector/explanations/privacy-security/key-binding.md) issued to the user's wallet #### Overview[​](#overview "Direct link to Overview") You build an authentication flow where users prove possession of a credential bound to their wallet's private key. You set `require_cryptographic_holder_binding` to `true` in the presentation request, which instructs the connector to request a [Key Binding JWT (KB-JWT)](/eudiw-connector/explanations/privacy-security/key-binding.md)—a signed JWT proving the presenter controls the credential's private key—from the wallet. The callback then includes `kbSignatureIsValid` and `kbKeyId`—an RFC 7638 thumbprint of the holder's public key—that you use as a stable, privacy-preserving identifier to recognize returning users. **Time to implement**: 1–2 hours. #### Step 1: Create a presentation request with key binding[​](#step-1-create-a-presentation-request-with-key-binding "Direct link to Step 1: Create a presentation request with key binding") Call `POST /oidc4vp` with `require_cryptographic_holder_binding: true`. This parameter is not part of the [DCQL](/eudiw-connector/explanations/standards/dcql.md) specification—it is a connector API parameter that controls whether the connector requests a KB-JWT from the wallet. note The VCT values, requested claims, and credential values in this guide are examples. In production, use the VCT and claims defined by your authentication credential type. The key binding pattern is the same regardless of credential type. * cURL ```bash curl -X POST http://connector:8081/oidc4vp \ -H "Content-Type: application/json" \ -d '{ "dcql_query": { "credentials": [ { "id": "aoc", "format": "dc+sd-jwt", "meta": { "vct_values": ["urn:eudi:aoc:1"] }, "claims": [ { "path": ["account_id"] } ], "require_cryptographic_holder_binding": true } ] } }' ``` Example response: ```json { "state": "abc123", "same_device_request_uri": "openid4vp://?client_id=...&request_uri=https%3A%2F%2Fconnector.example.com%2Foidc4vp%2Fabc123%2Frequest%3Fflow_type%3Dsame-device", "cross_device_request_uri": "openid4vp://?client_id=...&request_uri=https%3A%2F%2Fconnector.example.com%2Foidc4vp%2Fabc123%2Frequest%3Fflow_type%3Dcross-device" } ``` Store the `state` value to correlate with the callback later. The format remains `dc+sd-jwt`—key binding is controlled by the `require_cryptographic_holder_binding` parameter, not by the format string. #### Step 2: Display the QR code or deep link[​](#step-2-display-the-qr-code-or-deep-link "Direct link to Step 2: Display the QR code or deep link") Use `cross_device_request_uri` for QR codes and `same_device_request_uri` for deep links, the same way as in the [KYC verification guide](/eudiw-connector/how-to-guides/integration-scenarios/kyc-verification.md#step-2-display-the-qr-code-or-deep-link). #### Step 3: Implement the callback handler[​](#step-3-implement-the-callback-handler "Direct link to Step 3: Implement the callback handler") Implement a callback endpoint that receives the `PresentedCredentialsEvent` from the connector. The `state` field correlates the event with your original request. For same-device flows, the `responseCode` field correlates the browser redirect with the callback. The authentication callback includes two fields beyond a standard credential verification: * `kbSignatureIsValid`: `true` if the wallet proved possession of the private key bound to the credential. Reject the login if this is `false`. * `kbKeyId`: an RFC 7638 JWK Thumbprint of the holder's public key. The same wallet with the same credential always produces the same `kbKeyId`. Use it as a stable user identifier. The `credentials` and `credentialsRaw` fields are absent for `REJECTED`, `EXPIRED`, `PROCESSING_ERROR`, and `VERIFICATION_FAILED` statuses. The `errorDetails` field is present for `REJECTED`, `PROCESSING_ERROR`, and `VERIFICATION_FAILED` statuses. * cURL ```bash # Simulate a FULFILLED callback with key binding for testing curl -X POST http://localhost:3000/callback/auth \ -H "Content-Type: application/json" \ -d '{ "status": "FULFILLED", "state": "abc123", "responseCode": "iaBjmfYXonNRo6MdqLQEsA", "credentials": { "aoc": [ { "issuer": "https://issuer.example.com", "claims": { "account_id": "04171643" }, "signatureIsValid": true, "supportRevocation": false, "supportTrustAnchor": true, "isTrusted": false, "kbSignatureIsValid": true, "kbKeyId": "KrXxHnYsf-Inp0hW1M6r32JfOZfEGX7QTr7wa-bnXlM" } ] }, "credentialsRaw": { "aoc": [ { "claims": "eyJhY2NvdW50X2lkIjoiMDQxNzE2NDMifQ==", "issuer": "https://issuer.example.com", "kbKeyId": "KrXxHnYsf-Inp0hW1M6r32JfOZfEGX7QTr7wa-bnXlM" } ] } }' ``` For the complete list of statuses and error codes, see the [callback events reference](/eudiw-connector/reference/callback-events.md). #### Testing[​](#testing "Direct link to Testing") ##### Test checklist[​](#test-checklist "Direct link to Test checklist") * Presentation request creates with `require_cryptographic_holder_binding: true` * Callback receives `kbSignatureIsValid` and `kbKeyId` in the `FULFILLED` payload * The `kbKeyId` is stable across multiple authentication attempts from the same wallet * Failed key binding proof (`kbSignatureIsValid: false`) is rejected * Callback handles all five statuses (`FULFILLED`, `REJECTED`, `EXPIRED`, `PROCESSING_ERROR`, `VERIFICATION_FAILED`) * Same-device flow correctly uses `responseCode` for browser redirect correlation #### Troubleshooting[​](#troubleshooting "Direct link to Troubleshooting") ##### Missing kbKeyId[​](#missing-kbkeyid "Direct link to Missing kbKeyId") Verify that `require_cryptographic_holder_binding` is not explicitly set to `false` in the request body. The field defaults to `true` when omitted, so the connector requests a key binding proof by default. If the field is set to `false`, the connector does not request a key binding proof, and `kbKeyId` and `kbSignatureIsValid` are absent from the callback payload. ##### Callback not receiving events[​](#callback-not-receiving-events "Direct link to Callback not receiving events") The connector delivers callbacks synchronously with a default two-second timeout per attempt and one retry. Verify that your callback endpoint is reachable from the connector and responds within the timeout. ##### Unstable user identifier[​](#unstable-user-identifier "Direct link to Unstable user identifier") The `kbKeyId` is derived from the holder's public key using RFC 7638. It remains stable as long as the user presents the same credential from the same wallet. If the user re-provisions their wallet or obtains a new credential, the `kbKeyId` changes. #### Next steps[​](#next-steps "Direct link to Next steps") * [KYC verification](/eudiw-connector/how-to-guides/integration-scenarios/kyc-verification.md)—verify customer identity using PID credentials * [Error handling](/eudiw-connector/how-to-guides/error-handling.md)—build robust status handling for all verification outcomes * [Going to production](/eudiw-connector/how-to-guides/going-to-production.md)—production readiness checklist #### Further reading[​](#further-reading "Direct link to Further reading") * [Key binding explained](/eudiw-connector/explanations/privacy-security/key-binding.md)—how holder binding works in the EUDI ecosystem * [Authentication use case](/eudiw-connector/explanations/use-cases/authentication.md)—conceptual overview of passwordless authentication * [Error codes](/eudiw-connector/reference/error-codes.md)—wallet-facing HTTP error responses * [Callback events](/eudiw-connector/reference/callback-events.md)—Presented Credentials Event statuses and payload fields --- ### Use transactional data Transactional data (the `transaction_data` parameter in OID4VP) is an optional parameter that binds contextual information to a presentation request. The wallet displays this data to the user during the consent step and authenticates it by including it in the [device binding](/eudiw-connector/explanations/privacy-security/key-binding.md) signature. The hashes returned in the response are a product of this cryptographic binding, allowing you to verify that the user approved the specific context. This guide shows you how to construct, encode, and verify transactional data with the Truvity EUDIW Connector. Transactional data is a general mechanism applicable to any use case: session binding, document references, payment authorization, or any scenario where you need to prove the user consented to a specific context. note Transactional data is the mechanism through which EUDI Wallets support Strong Customer Authentication (SCA)—a requirement under the [Payment Services Directive (PSD2)](https://eur-lex.europa.eu/legal-content/EN/TXT/?uri=celex%3A32015L2366), the EU regulation governing electronic payment services, that mandates two of three authentication factors (knowledge, possession, inherence) for electronic payments. In the SCA context, the transactional data must include at least the payment amount and the payee. The SCA use case requires a prior registration step where the user's wallet receives a dedicated Secure User Authentication (SUA) attestation—a credential issued to the wallet during a registration step with the Relying Party that authorizes the wallet to perform SCA-protected operations. Prerequisites * Completed the [verification quickstart](/eudiw-connector/getting-started/verify-credentials.md) #### Overview[​](#overview "Direct link to Overview") You build a presentation request that includes transactional data, then verify in the callback that the wallet acknowledged the bound data. This ensures that a presentation intended for one transaction cannot be replayed in a different context. note The structure and semantics of transactional data objects depend on the applicable [Attestation Rulebook](/eudiw-connector/reference/glossary.md#regulatory-and-compliance) for the credential type being requested. The examples in this guide are illustrative; production implementations should follow the Rulebook for their specific use case. The ARF also defines transactional data support for proximity flows via ISO/IEC 18013-5; this guide covers the remote (OID4VP) flow implemented by the connector. **Time to implement**: 1 hour. #### Step 1: Construct transactional data objects[​](#step-1-construct-transactional-data-objects "Direct link to Step 1: Construct transactional data objects") Each transactional data object contains a `type` field that identifies the transaction context and a `credential_ids` array referencing [DCQL](/eudiw-connector/explanations/standards/dcql.md) credential IDs that can authorize the transaction. These two fields are defined by the OID4VP specification. Additional fields (for example, `amount` and `payee` for a payment context) are defined by the applicable Attestation Rulebook for the credential type being requested. Examples for common use cases: **Session binding**—bind a login session to the presentation: ```json { "type": "login_session", "credential_ids": ["pid_auth"] } ``` **Document reference**—bind a document signing context to the presentation: ```json { "type": "document_signing", "credential_ids": ["pid_kyc"] } ``` **Payment context**—bind a payment authorization to the presentation: ```json { "type": "payment_authorization", "credential_ids": ["pid_kyc"] } ``` #### Step 2: Include transactional data in the request[​](#step-2-include-transactional-data-in-the-request "Direct link to Step 2: Include transactional data in the request") Include the transactional data objects in the `transaction_data` array of the `POST /oidc4vp` request body. The connector serializes and base64url-encodes the objects before including them in the authorization request JWT's `transaction_data` field. * cURL ```bash curl -X POST http://connector:8081/oidc4vp \ -H "Content-Type: application/json" \ -d '{ "dcql_query": { "credentials": [ { "id": "pid_kyc", "format": "dc+sd-jwt", "meta": { "vct_values": ["urn:eudi:pid:1"] }, "claims": [ { "path": ["given_name"] }, { "path": ["family_name"] } ] } ] }, "transaction_data": [ { "type": "payment_authorization", "credential_ids": ["pid_kyc"] } ] }' ``` Example response: ```json { "state": "abc123", "same_device_request_uri": "openid4vp://?client_id=...&request_uri=https%3A%2F%2Fconnector.example.com%2Foidc4vp%2Fabc123%2Frequest%3Fflow_type%3Dsame-device", "cross_device_request_uri": "openid4vp://?client_id=...&request_uri=https%3A%2F%2Fconnector.example.com%2Foidc4vp%2Fabc123%2Frequest%3Fflow_type%3Dcross-device" } ``` Store the `state` value for verification in the callback. #### Step 3: Verify transactional data in the callback[​](#step-3-verify-transactional-data-in-the-callback "Direct link to Step 3: Verify transactional data in the callback") When the callback arrives with a `FULFILLED` status, each `PresentedCredential` includes a `transactionDataHashes` array. These hashes are a product of the wallet's device binding signature—the wallet authenticates the transactional data by including it in the device binding process, so no separate signed response field is needed. Verify these hashes against locally computed hashes of the original base64url-encoded transactional data strings to confirm the wallet acknowledged the bound data. * cURL ```bash # Simulate a FULFILLED callback with transactionDataHashes for testing. # In production, the connector delivers this payload to your callback endpoint. curl -X POST http://localhost:3000/callback \ -H "Content-Type: application/json" \ -d '{ "status": "FULFILLED", "state": "abc123", "responseCode": "", "credentials": { "pid_kyc": [ { "issuer": "https://issuer.example.com", "claims": { "given_name": "Erika", "family_name": "Mustermann" }, "signatureIsValid": true, "supportRevocation": false, "supportTrustAnchor": true, "isTrusted": false, "kbKeyId": "", "kbSignatureIsValid": true, "transactionDataHashes": [""], "validFrom": "2026-01-15T10:30:00Z", "validUntil": "2026-07-15T10:30:00Z" } ] }, "credentialsRaw": { "pid_kyc": [ { "claims": "", "issuer": "https://issuer.example.com", "kbKeyId": "", "transactionDataHashes": [""], "validFrom": "2026-01-15T10:30:00Z", "validUntil": "2026-07-15T10:30:00Z" } ] } }' ``` The `responseCode` field is present only in same-device flows. If you use a cross-device flow, the callback omits `responseCode`. #### Testing[​](#testing "Direct link to Testing") ##### Test checklist[​](#test-checklist "Direct link to Test checklist") * Transactional data encodes correctly as base64url strings * Presentation request includes `transaction_data` in the request body * Callback contains `transactionDataHashes` in the `PresentedCredential` * Hash verification succeeds for matching transactional data * Hash verification fails for tampered transactional data * Multiple transactional data items encode and verify correctly #### Troubleshooting[​](#troubleshooting "Direct link to Troubleshooting") ##### Missing transactionDataHashes in callback[​](#missing-transactiondatahashes-in-callback "Direct link to Missing transactionDataHashes in callback") Verify that you included the `transaction_data` array in the `POST /oidc4vp` request body. The `transactionDataHashes` field is only present when transactional data was included in the original request. ##### Hash mismatch[​](#hash-mismatch "Direct link to Hash mismatch") Ensure you compute the hash over the exact base64url-encoded string you sent in the request, not the decoded JSON. The hash input is the encoded string, not the raw JSON object. #### Next steps[​](#next-steps "Direct link to Next steps") * [KYC verification](/eudiw-connector/how-to-guides/integration-scenarios/kyc-verification.md)—implement identity verification with transactional data binding * [Error handling](/eudiw-connector/how-to-guides/error-handling.md)—handle all verification outcomes in your callback #### Further reading[​](#further-reading "Direct link to Further reading") * [DCQL query language](/eudiw-connector/explanations/standards/dcql.md)—how to specify credential requirements and transactional data context * [OID4VP protocol](/eudiw-connector/explanations/standards/oid4vp-protocol.md)—how transactional data is bound to the authorization request * [Device binding](/eudiw-connector/explanations/privacy-security/key-binding.md)—how the wallet cryptographically signs transactional data * [Error codes](/eudiw-connector/reference/error-codes.md)—wallet-facing HTTP error responses * [Callback events](/eudiw-connector/reference/callback-events.md)—Presented Credentials Event statuses and payload fields --- ### Use transaction codes This guide shows you how to add transaction code (tx\_code) authorization to your credential issuance flows with the Truvity EUDIW Connector. A transaction code is a one-time code that the user must enter in their wallet before the credential is issued, providing an additional layer of authorization beyond the pre-authorized code. Prerequisites * Completed the [issuance quickstart](/eudiw-connector/getting-started/issue-credentials.md) * Familiarity with [credential issuance](/eudiw-connector/how-to-guides/credential-issuance.md) #### Overview[​](#overview "Direct link to Overview") Transaction codes add an additional authorization layer to credential issuance. When you include a `tx_code` configuration in your offer request, the connector generates a one-time code that you deliver to the user through a separate channel (for example, SMS or email). The user enters this code in their wallet, and the [authorization server](/eudiw-connector/explanations/architecture/connector-architecture.md) validates it at the token endpoint before issuing an access token as part of the [pre-authorized code flow](/eudiw-connector/explanations/standards/oid4vci-protocol.md). Use transaction codes when: * Issuing high-value credentials that require additional user verification * Regulatory requirements mandate out-of-band authorization * You want to confirm the user requesting the credential controls a specific phone number or email address **Time to implement**: 30 minutes. #### Step 1: Create an offer with tx\_code[​](#step-1-create-an-offer-with-tx_code "Direct link to Step 1: Create an offer with tx_code") Call `POST /offers` on the management API with a `tx_code` object in the request body. The `tx_code` object specifies the code format (`input_mode`) and length. * cURL ```bash curl -X POST http://connector:8081/offers \ -H "Content-Type: application/json" \ -d '{ "credential_configuration_id": "AccountOwnershipCredential", "claims": { "bankName": "Example Bank", "accountHolder": "Erika Mustermann", "iban": "DE99370501981234567890" }, "tx_code": { "input_mode": "numeric", "length": 6, "description": "Enter the code sent to your phone" } }' ``` Example response: ```json { "offer_id": "abc123def456", "credential_offer_uri": "openid-credential-offer://?credential_offer_uri=https%3A%2F%2Fissuer.example.com%2Foidc4vci%2Foffers%2Fabc123def456", "tx_code_value": "679042" } ``` The request body includes the same `credential_configuration_id` and `claims` fields as a [standard credential offer](/eudiw-connector/how-to-guides/credential-issuance.md), plus: * `tx_code.input_mode`—the type of code the user enters. Supported values: `"numeric"` (digits only) or `"text"` (any characters). * `tx_code.length`—the number of characters in the code (for example, `6`). * `tx_code.description` (optional)—a human-readable description of the transaction code purpose that wallets can display to the user. The response includes the standard `offer_id` and `credential_offer_uri` fields, plus: * `tx_code_value`—the generated transaction code. Store this value and deliver it to the user through a separate channel. This field is only present when `tx_code` is included in the request. #### Step 2: Deliver the tx\_code to the user[​](#step-2-deliver-the-tx_code-to-the-user "Direct link to Step 2: Deliver the tx_code to the user") Send the `tx_code_value` to the user through a channel separate from the credential offer (for example, SMS or email). The user enters this code in their wallet when prompted during the issuance flow. What to implement Extract the `tx_code_value` from the offer response and deliver it to the user through your chosen channel. Your implementation should: * Retrieve the `tx_code_value` string from the `POST /offers` response. * Send it to the user via SMS, email, or in-app notification before the session expires (default five minutes). * Store the `offer_id` for callback correlation. For example, call your SMS gateway or email service with the code value immediately after creating the offer. Delivering the transaction code is your responsibility. The connector generates the code and returns it in the offer response, but does not send it to the user. Choose a delivery channel appropriate for your use case: * **SMS**—suitable for mobile-first flows where the user's phone number is verified. * **email**—suitable when the user's email address is verified. * **In-app notification**—suitable when the user is authenticated in your app. The wallet prompts the user to enter the transaction code before exchanging the pre-authorized code for an access token. The authorization server validates the code at the token endpoint. If the code is incorrect or expired, the authorization server rejects the token request with an `invalid_grant` error, and the wallet cannot proceed with the issuance flow. #### Step 3: Handle the callback[​](#step-3-handle-the-callback "Direct link to Step 3: Handle the callback") The callback payload for tx\_code flows uses the same structure as standard issuance callbacks. Handle all three statuses relevant to tx\_code flows: `OFFER_CREATED`, `ISSUED`, and `EXPIRED`. * cURL ```bash # Simulate an ISSUED callback (tx_code was correct, credential issued) curl -X POST http://backend.example.com:3000/callback/issuance \ -H "Content-Type: application/json" \ -d '{ "eventId": "abc123def456", "status": "ISSUED", "offerId": "abc123def456" }' # Simulate an EXPIRED callback (session expired — for example, user never entered the tx_code) curl -X POST http://backend.example.com:3000/callback/issuance \ -H "Content-Type: application/json" \ -d '{ "eventId": "abc123def456", "status": "EXPIRED", "offerId": "abc123def456" }' ``` When the user enters an incorrect transaction code, the authorization server rejects the token request with `invalid_grant`. The wallet cannot exchange the pre-authorized code for an access token, so the issuance flow stalls. The connector has no visibility into this failure because the wallet never reaches the credential endpoint. The session eventually expires, and the connector delivers an `EXPIRED` callback. Create a new offer with a fresh transaction code if the user wants to retry. For the complete list of callback payload fields and status descriptions, see the [callback events reference](/eudiw-connector/reference/callback-events.md). #### Testing[​](#testing "Direct link to Testing") ##### Test checklist[​](#test-checklist "Direct link to Test checklist") * Offer with `tx_code` returns `tx_code_value` in the response * Correct transaction code: issuance completes and callback receives `ISSUED` status * Incorrect transaction code: wallet receives `invalid_grant` from the authorization server and cannot proceed; session eventually expires and callback receives `EXPIRED` status * Expired session (user never entered the code): callback receives `EXPIRED` status * Transaction code is delivered to the user through the chosen channel * Retry flow creates a new offer with a fresh transaction code #### Troubleshooting[​](#troubleshooting "Direct link to Troubleshooting") ##### `invalid_grant` error from the authorization server[​](#invalid_grant-error-from-the-authorization-server "Direct link to invalid_grant-error-from-the-authorization-server") The authorization server returns `invalid_grant` when the transaction code is incorrect or has already been used. This error is returned to the wallet at the token endpoint—the connector does not receive a direct notification of this failure. The session remains in `OFFER_CREATED` state until it expires, at which point the connector sends an `EXPIRED` callback. Verify that: * The `tx_code_value` from the offer response is delivered to the user without modification. * The user enters the code before the session expires (default TTL is five minutes). * The code has not already been used in a previous token exchange attempt. Create a new offer with a fresh transaction code if the user needs to retry. ##### `tx_code_value` not delivered to the user[​](#tx_code_value-not-delivered-to-the-user "Direct link to tx_code_value-not-delivered-to-the-user") If the user does not receive the transaction code, the issuance flow stalls until the session expires. Check your delivery channel (SMS gateway, email service) for failures. The connector doesn't retry code delivery—this is your responsibility. ##### Transaction code expired before the wallet completes the flow[​](#transaction-code-expired-before-the-wallet-completes-the-flow "Direct link to Transaction code expired before the wallet completes the flow") The transaction code is tied to the session TTL (default five minutes). If users consistently time out, consider guiding them to enter the code promptly after receiving it, or adjust the session TTL if your deployment supports it. #### Next steps[​](#next-steps "Direct link to Next steps") * [Issue a credential](/eudiw-connector/how-to-guides/credential-issuance.md)—generic credential issuance without transaction codes * [Build an AOC issuance flow](/eudiw-connector/tutorials/aoc-issuance-tutorial.md)—end-to-end tutorial including optional tx\_code #### Further reading[​](#further-reading "Direct link to Further reading") * [OID4VCI protocol](/eudiw-connector/explanations/standards/oid4vci-protocol.md)—how the issuance protocol works * [Error codes](/eudiw-connector/reference/error-codes.md)—wallet-facing HTTP error responses * [Callback events](/eudiw-connector/reference/callback-events.md)—issuance event statuses and payload fields --- ### Compliance and regulations Integrating with EU Digital Identity Wallets requires compliance with multiple regulations and technical standards. This page explains what you need to know about eIDAS 2.0, the Architecture Reference Framework (ARF), and how Truvity EUDIW Connector addresses these requirements so you can focus on your business logic. This is not legal advice This documentation provides technical guidance on compliance requirements. For legal interpretation of regulations, consult your legal counsel. #### eIDAS 2.0[​](#eidas-20 "Direct link to eIDAS 2.0") The **eIDAS 2.0 Regulation** (Regulation EU 2024/1183) establishes the legal framework for European Digital Identity Wallets across the EU. It defines: * **Attestation providers**: Member states issue Personal Identification Data (PID), while qualified and non-qualified attestation providers issue Electronic Attestations of Attributes (EAA). * **Relying Parties**: Relying Parties and Relying Party Intermediaries registered with member state authorities can verify credentials. * **Protection**: The regulation mandates protection of user privacy, data minimization, and secure credential exchange. * **Trust establishment**: Trust is established through digital certificates, trusted lists (registries of authorized entities), and revocation mechanisms. A key principle is that **users control their digital identity**. Organizations can request but never force sharing of credentials. The ARF enforces [data minimization](/eudiw-connector/reference/glossary.md#regulatory-and-compliance) through two mechanisms. First, Relying Parties must register which attributes they intend to request, and Wallet Units can verify that a request does not exceed this registration. Second, [selective disclosure](/eudiw-connector/explanations/privacy-security/selective-disclosure.md) allows Relying Parties to request only specific attributes within an attestation rather than the entire attestation. User approval and data deletion User approval to present attributes from a Wallet Unit is not the same as GDPR consent for data processing. You must independently ensure you have a lawful basis under GDPR Article 6 for processing the personal data you receive. The ARF also enables users to request data deletion from Relying Parties through their Wallet Unit dashboard, in accordance with GDPR Article 17. Ensure you have procedures in place to handle such requests. **Effective dates**: * December 31, 2026: All EU member states must offer EUDI Wallets to citizens. * December 31, 2027: All businesses and online platforms must accept EUDI Wallets. For a detailed explanation of the eIDAS 2.0 legal framework and RPI obligations, see [eIDAS 2.0 requirements](/eudiw-connector/explanations/standards/eidas-2-requirements.md). #### Commission Implementing Regulations (Implementing Acts)[​](#commission-implementing-regulations-implementing-acts "Direct link to Commission Implementing Regulations (Implementing Acts)") eIDAS 2.0 is supported by several Implementing Regulations that provide technical details. Some of the most important include: **Commission Implementing Regulation (EU) 2024/2977** covers person identification data and electronic attestations of attributes requirements. It specifies mandatory and optional attributes for PID and EAA, as well as issuance requirements. **Commission Implementing Regulation (EU) 2024/2979** addresses wallet integrity and core functionalities, detailing security features, cryptographic requirements, and user interface standards. This regulation is primarily relevant to wallet providers rather than Relying Parties. **Commission Implementing Regulation (EU) 2024/2980** establishes requirements for Member State notifications to the Commission about trusted entities in the EUDI Wallet ecosystem, including wallet providers, PID providers, and registrars. **Commission Implementing Regulation (EU) 2024/2982** defines the protocols and interfaces for the EUDI Framework, covering credential issuance, attribute presentation to Relying Parties, data erasure requests, and Relying Party reporting to supervisory authorities. **Commission Implementing Regulation (EU) 2025/848** establishes rules for the registration of wallet-relying parties, including requirements for national registers, the information that Relying Parties must provide during registration, access certificates, and registration certificates. For a summary table of all Implementing Regulations, see [eIDAS 2.0 requirements](/eudiw-connector/explanations/standards/eidas-2-requirements.md). #### Architecture Reference Framework (ARF)[​](#architecture-reference-framework-arf "Direct link to Architecture Reference Framework (ARF)") The Architecture Reference Framework (ARF) is the technical blueprint that defines how EUDI Wallets, attestation providers, and Relying Parties interact. It translates eIDAS 2.0 legal requirements into specific technical specifications. ##### High-level requirements[​](#high-level-requirements "Direct link to High-level requirements") The ARF defines hundreds of requirements organized by topic. Key categories relevant to Relying Parties include: | Category | Description | Examples | | ------------------------- | ----------------------------------------------- | -------------------------------------------------- | | **RP Registration** | Requirements for registering as a Relying Party | Certificate issuance, intended use declaration | | **Presentation Protocol** | How to request and receive credentials | Authorization Request structure, response handling | | **Trust Evaluation** | Verifying credential authenticity | Signature validation, revocation checking | | **Privacy Protection** | User data handling requirements | Selective disclosure, data minimization | | **RPI Operations** | Requirements for intermediaries | No data storage, transparent operation | For the detailed ARF structure, requirement categories, and how the ARF translates eIDAS 2.0 into technical specifications, see [Architecture Reference Framework (ARF)](/eudiw-connector/explanations/standards/arf-overview.md). #### High Assurance Interoperability Profile (HAIP)[​](#high-assurance-interoperability-profile-haip "Direct link to High Assurance Interoperability Profile (HAIP)") The High Assurance Interoperability Profile (HAIP) ensures: * **Cross-border interoperability**: Wallets and RPs from different member states work together seamlessly. * **High assurance level**: Cryptographic strength suitable for government and financial services. * **Consistent implementation**: All parties follow the same security requirements. The EUDIW Connector follows HAIP specifications for both verification and issuance flows, ensuring compatibility with official EUDI Wallets across all EU member states. For detailed HAIP specifications, cryptographic requirements, and how the connector implements the profile, see [High Assurance Interoperability Profile (HAIP)](/eudiw-connector/explanations/standards/haip.md). #### Ephemeral data model[​](#ephemeral-data-model "Direct link to Ephemeral data model") The connector uses an [ephemeral data model](/eudiw-connector/explanations/privacy-security/ephemeral-data-model.md) as a security architecture choice that minimizes the attack surface. Credential data is processed in memory, verified, delivered to your callback, and then deleted. No user attributes persist in the connector. This design reduces the risk of data breaches by ensuring sensitive identity data does not accumulate in storage. #### Certificate requirements[​](#certificate-requirements "Direct link to Certificate requirements") The EUDI ecosystem uses certificates for both Relying Parties (verifiers) and credential issuers. ##### Verification certificates[​](#verification-certificates "Direct link to Verification certificates") **Access certificates** authenticate the Relying Party to EUDI Wallets during credential requests. They function like digital ID cards, proving that a request comes from a legitimate, registered party. The ARF distinguishes between a Relying Party (the legal entity) and a Relying Party Instance (the technical system that interacts with Wallet Units). Each Relying Party Instance requires its own access certificate. **Registration certificates** describe the Relying Party's registered intended uses and the attributes it has registered to request. These contain your organization's declared purposes (for example, "KYC for bank account opening") and the specific credential types and attributes you intend to request. Registration certificates are optional—not all member states issue them. When a registration certificate is not available, the Wallet Unit retrieves the same information from the Registrar's online service. ##### Issuance certificates[​](#issuance-certificates "Direct link to Issuance certificates") **Issuer Signing Certificate** signs the credentials your organization issues to wallet holders. This certificate is included in the credential's cryptographic header so wallets can verify the credential's authenticity. It uses a separate cryptographic key from the verification access certificate. **Access certificate** (in the issuance context) proves your organization's participation in the EUDI ecosystem and signs your issuer metadata. Wallets use this to verify that your connector is a legitimate credential issuer. This may be the same certificate used for verification or a separate one. To obtain these certificates, you first register with a Registrar in your member state. After successful registration, an [Access Certificate Authority](/eudiw-connector/reference/glossary.md#eudi-wallet-ecosystem) issues your access certificates, and a [Provider of Registration Certificates](/eudiw-connector/reference/glossary.md#eudi-wallet-ecosystem) may issue registration certificates if the member state supports them. You then configure these certificates in the connector. For detailed information on certificate lifecycle, trust chain validation, and generating issuance certificates, see [Certificates in EUDI](/eudiw-connector/explanations/trust-revocation/certificates.md) and the [certificates how-to guide](/eudiw-connector/how-to-guides/certificates.md). #### Further reading[​](#further-reading "Direct link to Further reading") * [What is the EUDIW Connector?](/eudiw-connector/overview/what-is-eudiw-connector.md)—product introduction and deployment * [EUDI Wallet ecosystem context](/eudiw-connector/overview/ecosystem-context.md)—roles, terminology, and architecture * [Use cases](/eudiw-connector/overview/use-cases.md)—real-world implementation scenarios * [OID4VCI protocol](/eudiw-connector/explanations/standards/oid4vci-protocol.md)—how the credential issuance protocol works --- ### EUDI Wallet ecosystem context The EU Digital Identity Wallet (EUDI Wallet) ecosystem represents a fundamental shift in how European citizens prove their identity and share verified information online. This page explains the key roles, terminology, and architecture patterns that make up this ecosystem, and shows how Truvity EUDIW Connector fits into the broader digital identity landscape. #### The digital identity triangle of trust[​](#the-digital-identity-triangle-of-trust "Direct link to The digital identity triangle of trust") The EUDI Wallet ecosystem builds on the concept of the **Triangle of Trust**—a model that defines how trust is established between three key parties in digital identity interactions. Background If you're familiar with Self-Sovereign Identity (SSI) concepts (a model where individuals control their own digital identity data without relying on a central authority), the EUDI ecosystem extends the traditional [Triangle of Trust](/ssi/overview/core-concepts/triangle-of-trust.md) with EU-specific regulations, standards, and infrastructure. ##### Core roles[​](#core-roles "Direct link to Core roles") Every credential exchange in the EUDI ecosystem involves three fundamental roles and one optional role. ###### 1. PID and attestation providers (issuers)[​](#1-pid-and-attestation-providers-issuers "Direct link to 1. PID and attestation providers (issuers)") **Issuers** are government agencies, banks, universities, and other trusted organizations that issue digital credentials. They create and digitally sign verifiable credentials containing verified attributes and cryptographic proofs of authenticity. Examples include: * A government issuing **Personal Identification Data (PID)**, the digital equivalent of a national ID card containing attributes like name, date of birth, and nationality. * A university issuing educational qualifications (diplomas, certificates). * A bank issuing proof of account ownership or creditworthiness. * An employer issuing professional licenses or certifications. In the EUDI context, credentials issued by [qualified or non-qualified attestation providers](/eudiw-connector/reference/glossary.md) (such as educational or financial institutions) are called **Electronic Attestations of Attributes (EAA)**. ###### 2. Wallet holders (users)[​](#2-wallet-holders-users "Direct link to 2. Wallet holders (users)") **Wallet holders** are EU citizens and residents who own and control an EUDI Wallet app. They store credentials received from issuers, decide what information to share, and present credentials to verifiers. Key characteristics of wallet holders: * **User control**: They decide when and with whom to share credentials. * **Privacy protection**: They can use selective disclosure to share only required attributes. * **Device-based**: Wallets run on their personal devices (smartphones, tablets). * **Multi-credential**: Wallets can hold PIDs, educational credentials, professional licenses, and more. ###### 3. Relying Parties (verifiers)[​](#3-relying-parties-verifiers "Direct link to 3. Relying Parties (verifiers)") **Relying Parties (RPs)** are organizations that need to verify user credentials to provide services or grant access. They request specific credentials, verify their authenticity and validity, and make decisions based on the information. Examples include banks verifying identity for KYC, airlines checking identity for boarding, government services determining benefit eligibility, and employers verifying qualifications. When you integrate the EUDIW Connector, your organization acts as a Relying Party. ###### 4. Relying Party Intermediaries (RPIs)[​](#4-relying-party-intermediaries-rpis "Direct link to 4. Relying Party Intermediaries (RPIs)") The Architecture Reference Framework (ARF) defines the **Relying Party Intermediary (RPI)** role as a specialized service provider that acts on behalf of a Relying Party to handle the technical complexity of wallet interactions. RPIs provide infrastructure for verification, trust evaluation, and protocol implementation. According to eIDAS 2.0 Article 5b(10), RPIs "shall not store data about the content of the transaction." They verify and forward credential data but cannot persist user attributes. Under the regulation, intermediaries are deemed to be Relying Parties themselves and must register with a Registrar. note The RPI role is defined by eIDAS 2.0 and the Architecture Reference Framework. It is described here for ecosystem context. The Truvity EUDIW Connector's current [deployment models](/eudiw-connector/overview/what-is-eudiw-connector.md#deployment) do not use the RPI role—your organization acts as the Relying Party directly. ##### Trust framework[​](#trust-framework "Direct link to Trust framework") The trust framework ensures verifiers can trust credentials without prior knowledge of the issuer: 1. **Issuers and RPs are registered**: Attestation providers and Relying Parties register with a Registrar designated by their member state. Registrars maintain the official list of registered entities. 2. **Credentials are signed**: Each credential contains a cryptographic signature from the issuer. 3. **Wallets prove possession**: Key binding proves the presenter legitimately holds the credential. 4. **Verifiers check everything**: Relying Parties verify signatures, check revocation status, and validate trust chains. Deep dive For detailed explanation of trust establishment mechanisms, certificate chains, cross-border trust, and comparison to other trust models, see [Trust establishment](/eudiw-connector/explanations/trust-revocation/trust-establishment.md). #### Where Truvity fits in the ecosystem[​](#where-truvity-fits-in-the-ecosystem "Direct link to Where Truvity fits in the ecosystem") Truvity is a solution provider. The EUDIW Connector is available as a [Dedicated deployment](/eudiw-connector/overview/what-is-eudiw-connector.md#dedicated) (managed by Truvity on your behalf) or [Self-managed](/eudiw-connector/overview/what-is-eudiw-connector.md#self-managed) (operated by you). In both models, the connector handles the complexity of protocol implementation, cryptographic operations, and compliance requirements, acting as the bridge between your app and the EUDI Wallet ecosystem. The connector enables your organization to participate in the EUDI ecosystem in two roles: * **As a Relying Party (verifier)**: you request and verify credentials from wallet holders using the [OID4VP protocol](/eudiw-connector/explanations/standards/oid4vp-protocol.md). The connector handles trust evaluation, signature validation, credential verification, and delivers verified data to your [callback](/eudiw-connector/explanations/architecture/connector-architecture.md). * **As a credential issuer**: you issue digital credentials to wallet holders using the [OID4VCI protocol](/eudiw-connector/explanations/standards/oid4vci-protocol.md). The connector handles the issuance protocol exchange, token management, cryptographic key binding, credential signing, and delivers issuance outcome notifications to your callback. Your organization owns the registration with a Registrar designated by your member state, manages your certificates, and controls all data processing. Wallet users always see your organization as the Relying Party or credential issuer. For detailed architecture diagrams, trust chains, and deployment patterns, see [Connector architecture](/eudiw-connector/explanations/architecture/connector-architecture.md). #### Key terminology[​](#key-terminology "Direct link to Key terminology") The EUDI Wallet ecosystem uses specific terminology. For complete definitions, see the [Glossary](/eudiw-connector/reference/glossary.md). #### Further reading[​](#further-reading "Direct link to Further reading") * [What is the EUDIW Connector?](/eudiw-connector/overview/what-is-eudiw-connector.md)—product introduction * [Compliance and regulations](/eudiw-connector/overview/compliance-regulations.md)—eIDAS 2.0, ARF, and your compliance responsibilities * [Use cases](/eudiw-connector/overview/use-cases.md)—real-world scenarios for credential verification and issuance * [Connector architecture](/eudiw-connector/explanations/architecture/connector-architecture.md)—system components, data flow, and security design --- ### Use cases The Truvity EUDIW Connector enables secure, privacy-preserving credential verification and issuance across industries and scenarios. Each use case links to a conceptual explanation and an implementation guide. #### Know Your Customer (KYC)[​](#know-your-customer-kyc "Direct link to Know Your Customer (KYC)") Verify customer identity for regulated onboarding scenarios such as opening a bank account, purchasing an insurance policy, or registering for a government service. This flow replaces manual document uploads with government-issued Personal Identification Data (PID) verification, helping you meet Anti-Money Laundering (AML) and KYC requirements. * **[Read the explanation](/eudiw-connector/explanations/use-cases/kyc.md)**: Conceptual overview of the KYC flow and how it works. * **[Implement the flow](/eudiw-connector/how-to-guides/integration-scenarios/kyc-verification.md)**: Complete guide to implementing KYC verification with DCQL queries. #### Passwordless authentication[​](#passwordless-authentication "Direct link to Passwordless authentication") Replace passwords with cryptographically secure credentials that users control in their personal wallets. This flow eliminates password databases, resists phishing, and improves user experience with biometric approval. * **[Read the explanation](/eudiw-connector/explanations/use-cases/authentication.md)**: Understand the conceptual flow, key binding, and security benefits. * **[Implement the flow](/eudiw-connector/how-to-guides/integration-scenarios/passwordless-authentication.md)**: Step-by-step guide to implementing passwordless authentication. #### Account Ownership Credential (AOC) issuance[​](#account-ownership-credential-aoc-issuance "Direct link to Account Ownership Credential (AOC) issuance") Issue Account Ownership Credentials to customers' EUDI Wallets as part of a bank account opening flow. After verifying a customer's identity, your app issues an AOC that links the customer's wallet to their account, enabling passwordless authentication for future sessions. * **[Read the explanation](/eudiw-connector/explanations/use-cases/aoc-issuance.md)**: Conceptual overview of the AOC issuance flow, business context, and how it connects to passwordless authentication. * **[Implement the flow](/eudiw-connector/how-to-guides/integration-scenarios/aoc-issuance.md)**: Complete guide to implementing AOC issuance in a banking app. #### Further reading[​](#further-reading "Direct link to Further reading") * [What is the EUDIW Connector?](/eudiw-connector/overview/what-is-eudiw-connector.md)—product introduction and deployment model * [Compliance and regulations](/eudiw-connector/overview/compliance-regulations.md)—eIDAS 2.0 requirements and how the connector addresses them * [EUDI Wallet ecosystem context](/eudiw-connector/overview/ecosystem-context.md)—roles, trust relationships, and where the connector fits --- ### What is the EUDIW Connector? Truvity EUDIW Connector is an API-first solution that enables your organization to verify and issue digital credentials with EU Digital Identity Wallets (EUDI Wallets). The connector runs in dedicated infrastructure and you integrate it through a [REST API](/eudiw-connector/getting-started/verify-credentials.md). The connector handles the complexity of the [OpenID for Verifiable Presentations (OID4VP)](/eudiw-connector/explanations/standards/oid4vp-protocol.md) and [OpenID for Verifiable Credential Issuance (OID4VCI)](/eudiw-connector/explanations/standards/oid4vci-protocol.md) protocols, [eIDAS 2.0](/eudiw-connector/explanations/standards/eidas-2-requirements.md) compliance, and cryptographic operations, so you can focus on your business logic and user experience. #### The challenge[​](#the-challenge "Direct link to The challenge") Organizations across the EU face increasing pressure to adopt digital identity verification for customer onboarding, authentication, and regulatory compliance. The European Union's eIDAS 2.0 regulation mandates that member states provide EUDI Wallets to citizens by December 2026, creating both an opportunity and a challenge for businesses. Integrating with EUDI Wallets presents significant technical and regulatory hurdles. You must implement the OID4VP protocol, which requires deep expertise in OAuth 2.0, JWT encryption, and digital signature standards. The [Architecture Reference Framework (ARF)](/eudiw-connector/explanations/standards/arf-overview.md) defines hundreds of specific requirements that your implementation must satisfy. Managing X.509 access certificates, trust chains, and revocation checking adds operational complexity. Supporting multiple wallet implementations across EU member states requires continuous testing and updates as each country rolls out its infrastructure. Banks, insurance companies, government services, and other organizations need a solution that shields them from this complexity while maintaining full compliance, security, and interoperability across all EU member states. #### The solution[​](#the-solution "Direct link to The solution") Truvity is a solution provider whose software runs in dedicated infrastructure. The EUDIW Connector provides a complete infrastructure layer that sits between your systems and EUDI Wallets. You are the Relying Party—the connector handles protocol implementation, cryptographic operations, and compliance enforcement on your behalf. When you integrate the connector, you gain immediate access to the entire EUDI Wallet ecosystem without building the underlying infrastructure yourself. The connector maintains protocol compatibility as standards evolve, validates trust chains against member state registries, and helps your implementation remain aligned with eIDAS 2.0 requirements. The connector abstracts away complexity through a simple REST API. It handles protocol negotiation, encryption, signature validation, revocation checking, and trust evaluation. #### Key capabilities[​](#key-capabilities "Direct link to Key capabilities") ##### Same-device and cross-device flows[​](#same-device-and-cross-device-flows "Direct link to Same-device and cross-device flows") The connector supports users regardless of how they access your service. In the **same-device flow**, a user clicks a link on their phone, and their EUDI Wallet app opens automatically. They approve the request with biometric authentication, and your app immediately receives the verified data. This flow requires no device switching, making it the most direct path for mobile users. In the **cross-device flow**, a user visits your website on desktop and scans a QR code with their EUDI Wallet. They approve the request on their phone, and your desktop app receives the verified data. This enables credential verification in contexts where the wallet is not installed on the device being used. Both flows provide the same security guarantees and deliver identical credential data. The connector automatically handles session management, state synchronization, and timeout handling for both patterns. ##### Selective disclosure[​](#selective-disclosure "Direct link to Selective disclosure") EUDI Wallets enable users to share only the specific information required for a transaction. Instead of presenting an entire credential (like a full passport), users can selectively disclose individual attributes or prove properties without revealing exact values. For details, see [Selective disclosure](/eudiw-connector/explanations/privacy-security/selective-disclosure.md). ##### Cryptographic verification[​](#cryptographic-verification "Direct link to Cryptographic verification") Every credential presentation undergoes comprehensive verification before the connector delivers data to your systems. **Signature validation** ensures that trusted authorities issued credentials by validating digital signatures against issuer public keys. This confirms credentials have not been tampered with and come from legitimate sources. **Key binding** validation confirms that the presenter legitimately possesses the credential through cryptographic proofs. This prevents unauthorized parties from using stolen credentials. **Revocation checking** verifies credential status against issuer revocation lists in real time. If a credential has been revoked (due to loss, theft, or validity expiration), the presentation fails verification. All verification happens automatically. You receive only successfully verified credential data through your [callback](/eudiw-connector/explanations/architecture/connector-architecture.md), with complete audit trails for compliance reporting. ##### Credential issuance[​](#credential-issuance "Direct link to Credential issuance") The connector enables your organization to issue digital credentials to EUDI Wallets using the [OpenID for Verifiable Credential Issuance (OID4VCI)](/eudiw-connector/explanations/standards/oid4vci-protocol.md) protocol. You create a credential offer through the management API, and the connector handles the protocol exchange with the wallet, including token management, cryptographic key binding, and credential signing. The connector supports the **pre-authorized code flow**, where your backend pre-authorizes credential issuance after authenticating the user. The wallet holder receives a credential offer as a QR code (cross-device) or deep link (same-device), approves the issuance in their wallet, and receives the signed credential. When the issuance flow completes, the connector delivers a callback to your backend with the outcome—whether the credential was successfully issued, the flow failed, or the session expired. This callback-based model lets you update your systems in response to issuance events without polling. ##### Certificate management[​](#certificate-management "Direct link to Certificate management") Digital certificates authenticate your organization to EUDI Wallets and establish trust in credential exchanges. You are responsible for obtaining and managing your certificates. The connector uses the following certificates: **For verification:** 1. **Access certificates** contain cryptographic keys for authenticating your Relying Party to wallets and ensure requests have not been tampered with. You obtain these from a Certificate Authority (CA) or member state registrar. 2. **Registration certificates** declare what data you can request and for what purposes. These contain registered intended uses (like "identity verification for account opening") and prove your authorization to request specific credentials and attributes. **For issuance:** 1. **Issuer Signing Certificate** signs the credentials your organization issues. This certificate is included in the credential's cryptographic header so wallets can verify the credential's authenticity. It uses a separate key from the verification access certificate. 2. **Access certificate** proves your organization's participation in the EUDI ecosystem and signs your issuer metadata. Wallets use this to verify that your connector is a legitimate credential issuer. For development purposes, the connector supports **self-signed certificates**. You can generate test certificates instantly to develop and test your integration without waiting for registration with member state authorities. These work for development but are not trusted by production wallets. For more details on certificate types and trust establishment, see the [certificates explanation](/eudiw-connector/explanations/trust-revocation/certificates.md). #### Deployment[​](#deployment "Direct link to Deployment") The connector supports two deployment models. In both, your organization acts as the Relying Party (RP) directly. ##### Dedicated[​](#dedicated "Direct link to Dedicated") Truvity deploys and manages a single-tenant connector instance on your behalf (for example, in a dedicated cloud account). You focus on integration and business logic while Truvity handles infrastructure operations, updates, and scaling. ##### Self-managed[​](#self-managed "Direct link to Self-managed") You deploy and manage the connector in your own infrastructure. This gives you full control over servers, networking, storage, and operational procedures. ##### What you need[​](#what-you-need "Direct link to What you need") Both deployment models require: * X.509 access certificates from a Certificate Authority (CA) or member state registrar * A [callback](/eudiw-connector/explanations/architecture/connector-architecture.md) endpoint to receive verification and issuance results * Relying Party registration with your member state authority * For issuance: an Issuer Signing Certificate and credential type metadata configured in the connector For details on certificates and trust establishment, see the [certificates explanation](/eudiw-connector/explanations/trust-revocation/certificates.md). For regulatory requirements, see [Compliance and regulations](/eudiw-connector/overview/compliance-regulations.md). #### Supported credential formats[​](#supported-credential-formats "Direct link to Supported credential formats") The connector supports the [SD-JWT VC](/eudiw-connector/explanations/credential-formats/sd-jwt.md) credential format defined by the Architecture Reference Framework (ARF). SD-JWT VC (SD-JWT-based Verifiable Credentials) combines selective disclosure with cryptographic key binding: * **Selective disclosure**: Holders share only the specific claims a Relying Party requests while keeping all other attributes private. Issuers sign the entire credential, and holders can prove they possess undisclosed claims without revealing their values. * **Key binding**: Cryptographic proof that the presenter legitimately possesses the credential. The wallet signs a challenge using a private key bound to the credential, preventing stolen credentials from being used by unauthorized parties. #### Benefits[​](#benefits "Direct link to Benefits") ##### Compliance-ready[​](#compliance-ready "Direct link to Compliance-ready") **eIDAS 2.0 aligned** The connector implements requirements from eIDAS 2.0 regulation (EU 2024/1183) for Relying Party operations. As regulatory updates and Implementing Acts are published, the connector is updated to reflect them. **ARF aligned** The connector follows the Architecture Reference Framework specifications for wallet interoperability. This includes alignment with high-level requirements for Relying Parties across all functional areas. **HAIP-first** The connector implements the [High Assurance Interoperability Profile (HAIP)](/eudiw-connector/explanations/standards/haip.md) to ensure compatibility with official EUDI Wallets from all EU member states. ##### Developer-friendly[​](#developer-friendly "Direct link to Developer-friendly") **REST API** The connector provides a simple, intuitive REST API following modern best practices. **Comprehensive documentation** Detailed guides cover every integration scenario—from KYC verification to passwordless authentication and credential issuance. Code examples, sequence diagrams, and troubleshooting guides accelerate your implementation. **Self-signed certificates** Start developing immediately without waiting for official registration. Generate self-signed access certificates and begin testing credential flows within minutes. ##### Secure by design[​](#secure-by-design "Direct link to Secure by design") **End-to-end encryption** All credential presentations use end-to-end encryption. The connector decrypts presentations only in memory, processes verification, and immediately discards encryption keys. **Ephemeral data model** The connector processes credential data in memory and delivers verified results to your callback. Encryption keys are created per request and deleted after use. This ephemeral approach minimizes the attack surface and reduces data breach risk. See the [ephemeral data model explanation](/eudiw-connector/explanations/privacy-security/ephemeral-data-model.md) for details. #### Get access[​](#get-access "Direct link to Get access") To get access to a connector instance, test credentials, and onboarding support, contact . #### Get started[​](#get-started "Direct link to Get started") Ready to integrate EUDI Wallet verification or issuance into your systems? 1. **Understand the ecosystem**: read [EUDI Wallet ecosystem context](/eudiw-connector/overview/ecosystem-context.md) to learn how the connector fits into the broader digital identity landscape and understand the roles of PIDs, attestation providers, wallet holders, and Relying Parties. 2. **Review compliance**: explore [Compliance and regulations](/eudiw-connector/overview/compliance-regulations.md) to understand eIDAS 2.0 requirements and your responsibilities as a Relying Party or credential issuer. 3. **Explore use cases**: see [Use cases](/eudiw-connector/overview/use-cases.md) for real-world scenarios including bank account opening (KYC), passwordless authentication, and Account Ownership Credential (AOC) issuance. 4. **Start building (verification)**: follow the [verification quickstart](/eudiw-connector/getting-started/verify-credentials.md) to create your first presentation request, implement a callback handler, and test the complete verification flow. 5. **Start building (issuance)**: follow the [issuance quickstart](/eudiw-connector/getting-started/issue-credentials.md) to create your first credential offer and issue a credential to a wallet. For a complete walkthrough, try the [AOC issuance tutorial](/eudiw-connector/tutorials/aoc-issuance-tutorial.md). #### Further reading[​](#further-reading "Direct link to Further reading") * [Ecosystem context](/eudiw-connector/overview/ecosystem-context.md)—roles, trust relationships, and where the connector fits * [Connector architecture](/eudiw-connector/explanations/architecture/connector-architecture.md)—system components, data flow, and security design * [Certificates](/eudiw-connector/explanations/trust-revocation/certificates.md)—access certificates, registration certificates, and trust establishment * [OID4VCI protocol](/eudiw-connector/explanations/standards/oid4vci-protocol.md)—how the credential issuance protocol works --- ### Callback events The Truvity EUDIW Connector delivers callback events to your [callback](/eudiw-connector/explanations/architecture/connector-architecture.md) endpoint during verification and issuance flows. Verification callbacks are sent at the end of the flow. Issuance callbacks are sent at multiple points—when the offer is created and when the flow completes. The `status` field indicates the outcome. #### Verification callback events[​](#verification-callback-events "Direct link to Verification callback events") The connector delivers a Presented Credentials Event at the end of each presentation flow. ##### Verification event statuses[​](#verification-event-statuses "Direct link to Verification event statuses") | Status | Description | | --------------------- | -------------------------------------------------------------------------------------------------- | | `FULFILLED` | Verification succeeded and credentials are available in the event payload | | `REJECTED` | The wallet declined the presentation request | | `EXPIRED` | The session expired before the wallet responded | | `PROCESSING_ERROR` | Internal processing failure (decryption, state validation) | | `VERIFICATION_FAILED` | Credential verification failed (invalid signatures, DCQL mismatch, transaction data hash failures) | ##### Verification payload fields by status[​](#verification-payload-fields-by-status "Direct link to Verification payload fields by status") The event payload contains different fields depending on the `status` value. | Field | `FULFILLED` | `REJECTED` | `EXPIRED` | `PROCESSING_ERROR` | `VERIFICATION_FAILED` | | ---------------- | ---------------- | ---------- | --------- | ------------------ | ------------------------------------ | | `status` | Always | Always | Always | Always | Always | | `state` | Always | Always | Always | Always | Always | | `credentials` | Present | Absent | Absent | Absent | Absent | | `credentialsRaw` | Present | Absent | Absent | Absent | Absent | | `errorDetails` | Absent | Present | Absent | Present | Present | | `responseCode` | Same-device only | Absent | Absent | Absent | Same-device only (trust enforcement) | ##### errorDetails field[​](#errordetails-field "Direct link to errorDetails field") The `errorDetails` field provides context for non-success statuses. | Status | `errorDetails` contents | | --------------------- | ----------------------------------------------------------------------------------------------------------------------------- | | `REJECTED` | The wallet's OAuth 2.0 error code and optional description (for example, `access_denied` or `access_denied: User canceled`) | | `PROCESSING_ERROR` | A human-readable description of the internal error (for example, decryption errors or state validation failures) | | `VERIFICATION_FAILED` | Credential verification failure details (for example, invalid signatures, DCQL mismatches, or transaction data hash failures) | ##### responseCode field[​](#responsecode-field "Direct link to responseCode field") For same-device flows, the event includes a `responseCode` field. The wallet redirects the user's browser back to your app with this code as a query parameter, allowing you to correlate the browser redirect with the callback event. The `responseCode` is also present on `VERIFICATION_FAILED` events caused by trust enforcement failures. In this scenario, the wallet submitted valid credentials (correct encryption and signatures), but the connector's trust policy rejected the issuer. Because the wallet already received the redirect, the backend needs the `responseCode` to correlate the user's browser redirect with the failure callback. #### Issuance callback events[​](#issuance-callback-events "Direct link to Issuance callback events") The connector delivers Issuance Events at various points during the issuance flow. ##### Issuance event statuses[​](#issuance-event-statuses "Direct link to Issuance event statuses") | Status | Description | | --------------- | -------------------------------------------------------- | | `OFFER_CREATED` | Credential offer was created successfully | | `ISSUED` | Credential successfully issued to the wallet | | `FAILED` | Issuance failed (issuer unavailable, internal error) | | `EXPIRED` | Session TTL expired before the wallet completed the flow | The `OFFER_CREATED` status is informational—it confirms the offer was created and the session is active. Use it for audit logging or to start a timeout timer in your backend. ##### Issuance payload fields by status[​](#issuance-payload-fields-by-status "Direct link to Issuance payload fields by status") | Field | `OFFER_CREATED` | `ISSUED` | `FAILED` | `EXPIRED` | | -------------- | --------------- | -------- | -------- | --------- | | `eventId` | Always | Always | Always | Always | | `status` | Always | Always | Always | Always | | `offerId` | Always | Always | Always | Always | | `errorDetails` | Absent | Absent | Present | Absent | * `eventId` (string)—correlation key tied to the offer lifecycle. Set to the same value as `offerId`, allowing you to group all status transitions for a single offer. To deduplicate retries of the same callback delivery, combine `eventId` with `status`. * `status` (string)—one of `OFFER_CREATED`, `ISSUED`, `FAILED`, or `EXPIRED` * `offerId` (string)—correlation with the original offer * `errorDetails` (string, nullable)—present for `FAILED` status, describes the failure reason ##### Issuance payload examples[​](#issuance-payload-examples "Direct link to Issuance payload examples") `OFFER_CREATED`: ```json { "eventId": "abc123def456", "status": "OFFER_CREATED", "offerId": "abc123def456" } ``` `ISSUED`: ```json { "eventId": "abc123def456", "status": "ISSUED", "offerId": "abc123def456" } ``` `FAILED`: ```json { "eventId": "abc123def456", "status": "FAILED", "offerId": "abc123def456", "errorDetails": "issuer service error: signing key validation failed" } ``` `EXPIRED`: ```json { "eventId": "abc123def456", "status": "EXPIRED", "offerId": "abc123def456" } ``` #### Credential object fields[​](#credential-object-fields "Direct link to Credential object fields") Each entry in the `credentials` map (present on `FULFILLED` events) is keyed by the credential ID from the DCQL query. Each value is an array of credential objects with the following fields. | Field | Type | Description | | ------------------------ | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `issuer` | string | The value of the credential's `iss` claim | | `claims` | object | The disclosed claims requested in the DCQL query, keyed by claim name | | `signatureIsValid` | boolean | Whether the credential's cryptographic signature is valid | | `kbSignatureIsValid` | boolean | Whether the key binding signature is valid. Present when the credential includes a key binding proof | | `kbKeyId` | string | The key identifier from the key binding proof. Present when `kbSignatureIsValid` is `true` | | `validFrom` | string | ISO 8601 timestamp from the credential's `iat` claim. Present when the credential includes an issued-at time | | `validUntil` | string | ISO 8601 timestamp from the credential's `exp` claim. Present when the credential includes an expiration time | | `supportRevocation` | boolean | Whether the credential includes a Status List revocation entry | | `isRevoked` | boolean | Whether the credential has been revoked via Status List. Present when `supportRevocation: true` | | `supportTrustAnchor` | boolean | Whether the credential was signed with an X.509 certificate chain (`x5c` header). When `true`, the `isTrusted` and `isCertificateRevoked` fields are also present | | `isTrusted` | boolean | Whether the certificate chain terminated at a configured trust anchor and the last certificate's signature was verified against it. Present when `supportTrustAnchor: true`. In LoTL-enabled mode, `true` means the issuer was resolved against the LoTL hierarchy or a static fallback anchor (non-qualified EAA only). `false` when trust anchor verification is off. See [Revocation mechanisms](/eudiw-connector/explanations/trust-revocation/revocation-mechanisms.md) and [LoTL trust verification](/eudiw-connector/explanations/trust-revocation/lotl-verification.md) | | `isCertificateRevoked` | boolean | Whether any certificate in the issuer's X.509 chain was found on a CRL. Present when `supportTrustAnchor: true`. `false` when trust anchor verification is off. See [Revocation mechanisms](/eudiw-connector/explanations/trust-revocation/revocation-mechanisms.md) | | `credentialCategory` | string | null | The credential's legal-effect classification. Values: `PID`, `QEAA`, `PUB_EAA`, `NON_QUALIFIED_EAA`. Present when `supportTrustAnchor: true` and the connector is running in LoTL-enabled mode. Absent in static-only mode. See [LoTL trust verification](/eudiw-connector/explanations/trust-revocation/lotl-verification.md) | | `trustSource` | string | null | Where trust was resolved. Values: `lotl` (resolved through the LoTL hierarchy), `static` (resolved against a configured static anchor), `untrusted` (could not be resolved). Present when `supportTrustAnchor: true` and the connector is running in LoTL-enabled mode. Absent in static-only mode. See [LoTL trust verification](/eudiw-connector/explanations/trust-revocation/lotl-verification.md) | | `supervisoryMemberState` | string | null | ISO 3166-1 alpha-2 code of the Member State whose supervisory body publishes the trust list containing the issuer's anchor. Present when `trustSource: "lotl"`. Absent for static-resolved or untrusted verifications | | `qualifiedStatus` | boolean | null | Whether the matched trust list entry is a qualified trust service. Present when `trustSource: "lotl"` | | `trustDataTimestamp` | string | null | ISO 8601 timestamp of the trust data snapshot used for this verification. Present when `supportTrustAnchor: true` and the connector is running in LoTL-enabled mode. Absent in static-only mode | | `trustFailureReason` | string | null | Coarse failure code when `isTrusted: false` and the connector is running in LoTL-enabled mode. Values: `issuer_not_found`, `issuer_withdrawn`, `issuer_suspended`, `trust_list_unavailable`. Absent when `isTrusted: true`. See [Configure trust anchor verification](/eudiw-connector/how-to-guides/configure-trust-anchors.md) | | `staleTrustData` | object | null | Present when `supportTrustAnchor: true` and the trust data used for verification was stale. Object with two boolean fields: `cachedFallback` (the connector used cached data because a fresh fetch failed) and `pastNextUpdate` (the cached data is past the publisher's declared next update). Absent when trust data is fresh | | `transactionDataHashes` | array | Hashes of transaction data included in the presentation. Present when the presentation request included transaction data | #### Raw credential object fields[​](#raw-credential-object-fields "Direct link to Raw credential object fields") Each entry in the `credentialsRaw` map (present on `FULFILLED` events) uses the same key structure as `credentials`. Each value is an array of raw credential objects with the following fields. | Field | Type | Description | | ----------------------- | ------ | ----------------------------------------------------------------------------------------------------------------------------------------- | | `claims` | string | Base64-encoded JSON containing the disclosed claims from the credential. Decode from base64 and then parse as JSON to access claim values | | `issuer` | string | The value of the credential's `iss` claim. Present when the credential includes an issuer | | `validFrom` | string | ISO 8601 timestamp from the credential's `iat` claim. Present when the credential includes an issued-at time | | `validUntil` | string | ISO 8601 timestamp from the credential's `exp` claim. Present when the credential includes an expiration time | | `kbKeyId` | string | The key identifier from the key binding proof. Present when the credential includes a key binding proof | | `transactionDataHashes` | array | Base64url-encoded transaction data hashes from the credential. Present when the credential includes transaction data | #### Further reading[​](#further-reading "Direct link to Further reading") * [Error codes](/eudiw-connector/reference/error-codes.md)—wallet-facing HTTP error responses * [Handle verification and issuance errors](/eudiw-connector/how-to-guides/error-handling.md)—implement error handling and retry logic for non-success statuses * [Issue a credential](/eudiw-connector/how-to-guides/credential-issuance.md)—create credential offers and handle issuance callbacks * [Connector architecture](/eudiw-connector/explanations/architecture/connector-architecture.md)—how the connector processes requests and delivers results * [Revocation mechanisms](/eudiw-connector/explanations/trust-revocation/revocation-mechanisms.md)—how credential and certificate revocation checking works * [LoTL trust verification](/eudiw-connector/explanations/trust-revocation/lotl-verification.md)—how trust anchor verification against the EU LoTL works --- ### Error codes This page lists the HTTP error responses that wallets encounter during verification and issuance flows with the Truvity EUDIW Connector. Some errors originate from the connector and others from the authorization server. #### Wallet-facing error responses[​](#wallet-facing-error-responses "Direct link to Wallet-facing error responses") When the connector encounters an error while processing a wallet request, it returns a JSON response with an `error` field and the corresponding HTTP status code. | Error code | HTTP status | Description | | ------------------------- | ----------- | ----------------------------------------------------------------------------------------------------- | | `invalid_request` | 400 | Validation errors during request parsing or format validation | | `invalid_request` | 403 | Cryptographic validation failures (signatures, key binding, nonce) or trust chain validation failures | | `server_error` | 500 | Infrastructure errors (database, key management) | | `temporarily_unavailable` | 503 | Transient errors (downstream service timeouts) | The `invalid_request` error code maps to two HTTP statuses because it covers two distinct failure categories defined by OID4VP. Use the HTTP status code to distinguish them: 400 indicates a malformed or missing request parameter, while 403 indicates a cryptographic or trust validation failure. #### Error description field[​](#error-description-field "Direct link to Error description field") Error responses may include an optional `error_description` field with a human-readable explanation of the error. This field provides additional context for debugging but is not guaranteed to be present in every response. #### Issuance error codes[​](#issuance-error-codes "Direct link to Issuance error codes") The connector and the authorization server return the following error codes to wallets during [OID4VCI](/eudiw-connector/explanations/standards/oid4vci-protocol.md) credential issuance flows. ##### Wallet-facing issuance error responses[​](#wallet-facing-issuance-error-responses "Direct link to Wallet-facing issuance error responses") | Error code | HTTP status | When returned | Resolution | | ---------------------------------- | ----------- | ----------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------ | | `invalid_proof` | 400 | Key Proof JWT is structurally invalid (wrong signature, `aud` mismatch, or expired `iat`) | Wallet creates a new Key Proof with the correct audience and a fresh timestamp | | `invalid_nonce` | 400 | `c_nonce` in Key Proof is invalid or expired | Wallet requests a fresh `c_nonce` from the nonce endpoint and retries | | `unknown_credential_configuration` | 400 | `credential_configuration_id` not found in Credential Issuer Metadata | Check that the credential configuration matches a configured type | | `unknown_credential_identifier` | 400 | `credential_identifier` not recognized (not found in the session or not matching any known configuration) | Check that the credential identifier matches a value from the token response | | `invalid_credential_request` | 400 | Credential request payload is malformed (missing required parameters, unsupported values) | Check request body structure against the OID4VCI specification | | `invalid_grant` | 400 | Pre-authorized code expired or already used, invalid `tx_code`, or session not found | Check offer expiration, verify `tx_code` delivery, confirm the offer has not been redeemed | | `invalid_token` | 401 | Access token invalid, expired, or DPoP thumbprint mismatch | Wallet must obtain a new token | | `invalid_request` | 400 | Request contains invalid parameters (for example, unsupported `tx_code` input mode) | Check request parameters against the API documentation | | `server_error` | 500 | Infrastructure errors (database, key management) | Retry after delay | | `temporarily_unavailable` | 503 | Transient errors (authorization server or credential signing service unavailable) | Wallet retries after delay | | `use_dpop_nonce` | 400 | [DPoP](/eudiw-connector/explanations/privacy-security/dpop.md) nonce required. Returned by the authorization server at the token endpoint | Wallet retries with the server-provided nonce from the `DPoP-Nonce` response header | #### Further reading[​](#further-reading "Direct link to Further reading") * [Callback events](/eudiw-connector/reference/callback-events.md)—verification and issuance callback event statuses and payload fields * [Connector architecture](/eudiw-connector/explanations/architecture/connector-architecture.md)—how the connector processes requests and delivers results * [Handle verification and issuance errors](/eudiw-connector/how-to-guides/error-handling.md)—implement error handling and retry logic * [Issue a credential](/eudiw-connector/how-to-guides/credential-issuance.md)—issue a credential of any type using the management API --- ### Glossary This page defines key terms used throughout the Truvity EUDIW Connector documentation. For callback payload field definitions, see [Callback events](/eudiw-connector/reference/callback-events.md). #### EUDI Wallet ecosystem[​](#eudi-wallet-ecosystem "Direct link to EUDI Wallet ecosystem") | Term | Definition | | ------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Attestation Provider** | Organization that issues credentials to wallet holders. Also referred to as "issuer" in protocol contexts. | | **Attestation Rulebook** | A specification defining the structure, semantics, and trust requirements for a specific credential type. | | **Attestation Scheme** | A specification defining the logical organization of attributes within an attestation, including identifiers, encoding, allowed values, and serialization. | | **Batch Issuance** | Issuing multiple instances of the same credential so the holder can use a different instance per presentation, reducing cross-session correlation. | | **Credential category** | The legal-effect classification of a presented credential—PID, QEAA, PuB-EAA, or non-qualified EAA. Determines which trust list the connector consults for issuer verification. See [LoTL trust verification](/eudiw-connector/explanations/trust-revocation/lotl-verification.md). | | **EAA** | Electronic Attestation of Attributes—any verified credential other than a PID (for example, a diploma or driver's license). | | **Issuance** | The process by which the connector creates and delivers a credential to a wallet holder using the OID4VCI protocol. The connector supports the pre-authorized code flow for issuance. | | **LoTE (List of Trusted Entities)** | A JSON-format registry (ETSI TS 119 602) publishing trust anchors for entities that are not trust service providers—PID Providers, Wallet Providers, and Access Certificate Authorities. See [Trust lists](/eudiw-connector/explanations/trust-revocation/trust-lists.md). | | **LoTL (List of Trusted Lists)** | The EU-managed root trust list published by the European Commission. It points to each Member State's national Trusted Lists and Lists of Trusted Entities, enabling the connector to discover trust anchors for credential issuers across the EU. See [LoTL trust verification](/eudiw-connector/explanations/trust-revocation/lotl-verification.md). | | **PID** | Personal Identification Data—government-issued digital identity credential. | | **PID Provider** | Organization authorized by a member state to issue PID credentials to wallet holders. | | **PuB-EAA** | EAA published under a specific legal basis other than the QTSP framework. | | **QEAA** | Qualified EAA—attestations from qualified trust service providers. | | **QTSP (Qualified Trust Service Provider)** | A trust service provider that meets the requirements of the eIDAS Regulation and is granted qualified status by a supervisory body. QTSPs issue qualified certificates used in the PuB-EAA trust chain. Their trust anchors are published in national Trusted Lists. | | **Registration Certificate** | A signed data object (JWT or CWT format, not X.509) that describes an organization's registered intended uses and indicates which credential types and attributes it has registered to request. Issued by a Provider of Registration Certificates after Relying Party registration. Optional—availability depends on member state policy. See [Certificates](/eudiw-connector/explanations/trust-revocation/certificates.md). | | **Relying Party (RP)** | Organization verifying credentials presented from a wallet. | | **Relying Party Instance** | A specific deployment of hardware and software that a Relying Party uses to interact with Wallet Units. | | **Relying Party Intermediary (RPI)** | A role defined by eIDAS 2.0 allowing a third party to act on behalf of a Relying Party. | | **Registrar** | An entity designated by a member state to register Relying Parties, PID Providers, and attestation providers. | | **Short-lived Attestation** | A credential with a validity period brief enough (typically under 24 hours) that revocation data is not required. | | **Triangle of Trust** | A trust model where attestation providers, wallet holders, and Relying Parties establish mutual trust through cryptographic proofs and a shared framework. | | **Wallet Holder** | An EU citizen or resident who owns and controls an EUDI Wallet, stores credentials, and decides when and with whom to share them. | | **Wallet Instance** | A specific installation of a wallet on a device. | | **Wallet Provider** | Organization that develops, operates, and maintains a Wallet Unit. | | **Wallet Unit** | The secure app on a user's device that stores and presents credentials. | | **WSCD** | Wallet Secure Cryptographic Device—the tamper-resistant component that stores private keys and performs cryptographic operations. | #### Protocols and standards[​](#protocols-and-standards "Direct link to Protocols and standards") | Term | Definition | | ------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Authorization Server** | The component that issues access tokens to wallets after validating pre-authorized codes and transaction codes. See [OID4VCI protocol](/eudiw-connector/explanations/standards/oid4vci-protocol.md). | | **DCQL** | Digital Credentials Query Language—format for specifying what credentials to request. See [DCQL](/eudiw-connector/explanations/standards/dcql.md). | | **DPoP** | Demonstration of Proof-of-Possession (RFC 9449)—mechanism for sender-constrained access tokens during issuance. See [DPoP](/eudiw-connector/explanations/privacy-security/dpop.md). | | **ES256** | ECDSA using the P-256 curve and SHA-256, the signing algorithm mandated by HAIP. | | **`etsi_tl`** | A DCQL authority type identifying issuers through the ETSI Trusted List format. Used in the `trusted_authorities` constraint to restrict which issuers the connector accepts for a presentation request. See [Verify a credential](/eudiw-connector/how-to-guides/credential-verification.md). | | **HAIP** | High Assurance Interoperability Profile—security requirements for OID4VP and OID4VCI. See [HAIP](/eudiw-connector/explanations/standards/haip.md). | | **JARM** | JWT-Secured Authorization Response Mode—encrypts credential delivery from wallet to Relying Party. | | **JWK Thumbprint** | A deterministic hash of a JSON Web Key's mathematical parameters as defined by RFC 7638. The connector uses JWK Thumbprints as the `kbKeyId` value to provide a stable, privacy-preserving identifier for wallet holders. | | **JWT** | JSON Web Token—a compact, URL-safe token format for representing claims between two parties (RFC 7519). | | **Key Binding (KB)** | Cryptographic proof that the presenter possesses the private key bound to a credential. See [Key binding](/eudiw-connector/explanations/privacy-security/key-binding.md). | | **mDoc** | Mobile Document format based on ISO 18013-5. | | **OAuth 2.0** | Authorization framework (RFC 6749) that OID4VP extends for credential presentation flows. | | **OID4VCI** | OpenID for Verifiable Credential Issuance—the protocol for issuing credentials to EUDI Wallets. See [OID4VCI protocol](/eudiw-connector/explanations/standards/oid4vci-protocol.md). | | **OID4VP** | OpenID for Verifiable Presentations—the protocol for requesting and receiving credentials. See [OID4VP](/eudiw-connector/explanations/standards/oid4vp-protocol.md). | | **SD-JWT** | Selective Disclosure JWT—credential format enabling selective disclosure of attributes. See [SD-JWT](/eudiw-connector/explanations/credential-formats/sd-jwt.md). | | **SD-JWT VC** | The Verifiable Credentials profile of SD-JWT, using the format identifier `dc+sd-jwt`. | | **Status List** | A published bitstring where each bit denotes the revocation or suspension status of one credential. See [Revocation mechanisms](/eudiw-connector/explanations/trust-revocation/revocation-mechanisms.md). | | **TLv6** | Trusted List version 6—the current version of the ETSI TS 119 612 trust list format, mandatory since April 29, 2026. | | **Token Endpoint** | The OAuth 2.0 endpoint where wallets exchange a pre-authorized code for a DPoP-bound access token. | | **VCT** | Verifiable Credential Type—a URI identifying the type of an SD-JWT VC credential. | | **Verifiable Credential (VC)** | A digitally signed credential issued by an attestation provider. | #### Regulatory and compliance[​](#regulatory-and-compliance "Direct link to Regulatory and compliance") | Term | Definition | | -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | **AML** | Anti-Money Laundering—regulations requiring organizations to detect and prevent money laundering. | | **ARF** | Architecture Reference Framework—technical blueprint for EUDI Wallet interactions. See [ARF overview](/eudiw-connector/explanations/standards/arf-overview.md). | | **Commission Implementing Regulation** | Detailed regulations implementing eIDAS 2.0 (for example, CIR 2024/2977, CIR 2024/2979, CIR 2024/2982, CIR 2025/848). | | **Data Minimization** | GDPR principle (Article 5(1)(c)) requiring that personal data collection be limited to what is necessary. | | **eIDAS 2.0** | European regulation (EU 2024/1183) establishing the legal framework for EUDI Wallets. See [eIDAS 2.0 requirements](/eudiw-connector/explanations/standards/eidas-2-requirements.md). | | **GDPR** | General Data Protection Regulation (EU 2016/679)—governs processing and protection of personal data. | | **KYC** | Know Your Customer—regulatory process requiring identity verification before providing services. | | **PSD2** | Payment Services Directive 2 (EU 2015/2366)—governs electronic payment services and requires SCA. | | **SCA** | Strong Customer Authentication—PSD2 requirement mandating two of three authentication factors for electronic payments. | #### Connector-specific terms[​](#connector-specific-terms "Direct link to Connector-specific terms") | Term | Definition | | --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **AOC** | Account Ownership Credential—a credential type used in the connector's tutorials to demonstrate passwordless authentication through key binding. You define your own VCT for production use. | | **Authorization Request** | The OID4VP request sent from the connector to a wallet, containing a DCQL query. | | **Callback** | The HTTP endpoint that receives [Presented Credentials Events](/eudiw-connector/reference/callback-events.md) and issuance events from the connector. See [Callback events](/eudiw-connector/reference/callback-events.md). | | **Credential Issuer Metadata** | The OID4VCI discovery document served at `GET /.well-known/openid-credential-issuer` describing the connector's issuer capabilities. See [OID4VCI protocol](/eudiw-connector/explanations/standards/oid4vci-protocol.md). | | **`credential_configuration_id`** | An OID4VCI identifier that selects which credential type to issue. Must match a credential type configured in the connector's [Type Metadata](/eudiw-connector/how-to-guides/credential-type-configuration.md). Passed in the `POST /offers` request body. | | **Credential offer** | An invitation from an issuer to a wallet holder to receive a credential, delivered as a QR code or deep link using the `openid-credential-offer://` URI scheme. | | **Credential Set** | A DCQL construct defining alternative credential combinations that satisfy a presentation request. | | **Cross-device flow** | OID4VP flow where the user scans a QR code on one device with their wallet on another device. | | **Deep link** | A URI (for example, `openid4vp://`) that opens the wallet app directly on the same device. | | **Ephemeral Data Model** | Architecture where credential data is never persisted—processed in memory and delivered via callback. See [Ephemeral data model](/eudiw-connector/explanations/privacy-security/ephemeral-data-model.md). | | **Fallback mode** | The configured behavior when a trust list source is unreachable and the cached snapshot exceeds the staleness window. See [Configure trust anchor verification](/eudiw-connector/how-to-guides/configure-trust-anchors.md). | | **Issuer Signing Certificate** | The X.509 certificate used by the connector to sign issued credentials. Must use a separate key pair from the access certificate. See [Manage certificates](/eudiw-connector/how-to-guides/certificates.md). | | **kbKeyId** | Key Binding Key Identifier—an RFC 7638 JWK Thumbprint derived from the holder's public key. Serves as a stable identifier for recognizing returning users across sessions. See [Key binding](/eudiw-connector/explanations/privacy-security/key-binding.md). | | **Management API** | The protected API on the connector's internal network interface (port 8081) used to create presentation requests and credential offers. | | **Presentation Response** | The wallet's encrypted response containing requested credentials. | | **Presented Credentials Event** | The payload delivered to the callback containing verification status and credentials. See [Callback events](/eudiw-connector/reference/callback-events.md). | | **Same-device flow** | OID4VP flow where the user and their wallet are on the same device, using a deep link. | | **Selective disclosure** | Privacy mechanism where holders share only the specific attributes requested. See [Selective disclosure](/eudiw-connector/explanations/privacy-security/selective-disclosure.md). | | **Signing Identity Key** | The private key associated with a Relying Party's X.509 access certificate, used to sign authorization requests. | | **Stale trust data** | A callback signal (`staleTrustData`) indicating that verification used trust data retrieved from cache after a fresh fetch failed (`cachedFallback`) or past the publisher's declared next update (`pastNextUpdate`). See [Callback events](/eudiw-connector/reference/callback-events.md). | | **Staleness window** | The maximum age of a cached trust list snapshot the connector honors after a fresh fetch fails, before failing closed. Default 24 hours. See [Configure trust anchor verification](/eudiw-connector/how-to-guides/configure-trust-anchors.md). | | **Transaction data** | An optional OID4VP parameter (`transaction_data`) that binds contextual information to a presentation request. The wallet displays this data during the consent step and includes its hash in the key-binding signature, allowing the Relying Party to verify user consent to a specific context. See [Use transactional data](/eudiw-connector/how-to-guides/transactional-data.md). | | **Trust failure reason** | The callback field providing a coarse failure code when `isTrusted` is `false` in LoTL-enabled mode—`issuer_not_found`, `issuer_withdrawn`, `issuer_suspended`, or `trust_list_unavailable`. See [Configure trust anchor verification](/eudiw-connector/how-to-guides/configure-trust-anchors.md). | | **Trust resolution mode** | The connector-instance configuration selecting how trust is resolved—`lotl` (LoTL-enabled, production) or `static` (static-only, fallback). See [Configure trust anchor verification](/eudiw-connector/how-to-guides/configure-trust-anchors.md). | | **Trust source** | The callback field indicating where trust was resolved for a credential—`lotl` (through the LoTL hierarchy), `static` (against a configured static anchor), or `untrusted` (could not be resolved). See [Callback events](/eudiw-connector/reference/callback-events.md). | | **Trust verification policy** | The per-credential-category configuration controlling how trust outcomes affect the callback: `enforce` (trust failure produces `VERIFICATION_FAILED`), `evaluate` (trust outcomes reported on `FULFILLED` payloads—the default), or `disabled` (trust fields omitted). See [Configure trust anchor verification](/eudiw-connector/how-to-guides/configure-trust-anchors.md). | | **tx\_code** | A transaction code providing additional authorization during credential issuance. Configured in the offer request and validated by the authorization server. See [Use transaction codes](/eudiw-connector/how-to-guides/tx-code.md). | | **Type Metadata** | A JSON configuration document defining a credential type the connector can issue. See [Configure credential types](/eudiw-connector/how-to-guides/credential-type-configuration.md). | #### Further reading[​](#further-reading "Direct link to Further reading") * [Callback events](/eudiw-connector/reference/callback-events.md)—payload field definitions and event statuses * [OID4VP protocol](/eudiw-connector/explanations/standards/oid4vp-protocol.md)—how the presentation protocol works * [OID4VCI protocol](/eudiw-connector/explanations/standards/oid4vci-protocol.md)—how the issuance protocol works * [Connector architecture](/eudiw-connector/explanations/architecture/connector-architecture.md)—system design and component interactions * [eIDAS 2.0 requirements](/eudiw-connector/explanations/standards/eidas-2-requirements.md)—regulatory context --- ### Tutorials Learn by building complete projects from scratch. Each tutorial produces a working integration you can use as a starting point for production. * **[KYC verification](/eudiw-connector/tutorials/kyc-tutorial.md)**—Verify customer identity using PID credentials from an EUDI Wallet (2–3 hours). * **[Passwordless authentication](/eudiw-connector/tutorials/auth-tutorial.md)**—Replace passwords with key-binding proof from a wallet credential (2–3 hours). * **[AOC issuance](/eudiw-connector/tutorials/aoc-issuance-tutorial.md)**—Issue an Account Ownership Credential after bank account opening (3–4 hours). All tutorials assume you completed the [verification quickstart](/eudiw-connector/getting-started/verify-credentials.md). The AOC issuance tutorial also requires the [issuance quickstart](/eudiw-connector/getting-started/issue-credentials.md). --- ### Build an AOC issuance flow In this tutorial, you walk through a complete credential issuance flow using the Truvity EUDIW Connector. You create a credential offer for an Account Ownership Credential (AOC), display it to a user's EUDI Wallet, and handle the issuance callback. By the end, you understand the full lifecycle—creating a credential offer, displaying it to the user, receiving issuance results, and handling errors—and have tested each step against the connector's API. You learn how to: * Call the connector's management API to create a credential offer * Generate a QR code for cross-device wallet interaction * Implement a deep link for same-device flows * Implement a callback endpoint that processes all issuance outcomes * Extend the flow with transaction code authorization Estimated time: 30–45 minutes. #### What you'll build[​](#what-youll-build "Direct link to What you'll build") Your integration needs two main components: 1. An offer endpoint that creates a credential offer for an AOC and displays a QR code for the user to scan with their EUDI Wallet. 2. A callback endpoint that receives the issuance result from the connector and updates your records based on the outcome. The user experience looks like this: a customer completes a bank account opening in your app, you create a credential offer containing their account details, the customer scans a QR code with their EUDI Wallet, approves the issuance, and your backend receives a callback confirming the credential was issued. No manual certificate exchange, no file downloads—a cryptographically signed credential delivered directly to the customer's wallet. Prerequisites * Completed the [issuance quickstart](/eudiw-connector/getting-started/issue-credentials.md) (Issuer Signing Certificate and Type Metadata configured) * Node.js 18+ development environment * Basic understanding of the [EUDI Wallet ecosystem](/eudiw-connector/overview/ecosystem-context.md) #### Step 1: Set up your project[​](#step-1-set-up-your-project "Direct link to Step 1: Set up your project") Start by creating a new project and installing the dependencies you need. The project uses an HTTP framework for the callback endpoint, an HTTP client for calling the connector's API, and a QR code library for displaying the credential offer. * Shell ```bash mkdir aoc-issuance && cd aoc-issuance npm init -y npm install express axios qrcode npm install -D @types/express @types/qrcode typescript ``` Here is what each dependency does: * **express / Spring Boot**: Hosts the callback endpoint that receives issuance results from the connector. * **axios / OkHttp**: Calls the connector's management API to create credential offers. * **qrcode / ZXing**: Generates QR codes from the connector's response URI so users can scan with their wallet. You also need an in-memory store to track issuance sessions. In production, you would use a database, but a simple map works for this tutorial. Session management Your integration needs an in-memory store to track issuance sessions. In production, use a database, but a simple map works for this tutorial. Create a session store that maps the connector's `offer_id` value to your app's session data (customer ID, status, timestamps). You use this store in the callback handler to correlate incoming results with the original offer. #### Step 2: Create a credential offer[​](#step-2-create-a-credential-offer "Direct link to Step 2: Create a credential offer") Now you create a credential offer that tells the connector which credential to issue and what claims to include. The offer uses the [OID4VCI](/eudiw-connector/explanations/standards/oid4vci-protocol.md) protocol's pre-authorized code flow, where your backend pre-authorizes the issuance without requiring the wallet holder to authenticate at an authorization server. The request goes to `POST /offers` on the connector's management API (port 8081). You provide the credential configuration ID (which references a type in your [Type Metadata](/eudiw-connector/how-to-guides/credential-type-configuration.md)) and the claims to embed in the credential. The connector creates a credential offer and returns three values: * `offer_id`—a correlation token you use to match the callback with this offer * `credential_offer_uri`—an `openid-credential-offer://` URI to render as a QR code or use as a deep link * `tx_code_value` (conditional)—present only when you include `tx_code` in the request (covered in Step 5) note The VCT value (`urn:eudi:aoc:1`) and claim values in this tutorial are examples for a typical AOC scenario. In production, use the VCT and claim structure defined in your [Type Metadata](/eudiw-connector/how-to-guides/credential-type-configuration.md). Available claims vary by credential type and issuer configuration. * cURL ```bash curl -X POST http://connector.example.com:8081/offers \ -H "Content-Type: application/json" \ -d '{ "credential_configuration_id": "AccountOwnershipCredential", "claims": { "bankName": "Example Bank", "accountHolder": "Erika Mustermann", "accountNumber": "1234567890", "iban": "DE99370501981234567890", "bic": "COLSDE33XXX", "currency": "EUR", "accountType": "checking", "sub": "user-uuid-123", "userId": "user-uuid-123" } }' ``` Example response (HTTP 201 Created): ```json { "offer_id": "abc123def456", "credential_offer_uri": "openid-credential-offer://?credential_offer_uri=https%3A%2F%2Fissuer.example.com%2Foidc4vci%2Foffers%2Fabc123def456" } ``` Store the `offer_id` to correlate with the callback later. Render `credential_offer_uri` as a QR code or redirect the user to it for same-device flows. A few things to notice in this code: * The `credential_configuration_id` references a credential configuration in the connector's [Credential Issuer Metadata](/eudiw-connector/explanations/standards/oid4vci-protocol.md). It must match a type defined in your [Type Metadata](/eudiw-connector/how-to-guides/credential-type-configuration.md). * The `claims` object contains the AOC-specific attributes: bank details (`bankName`, `iban`, `bic`), account details (`accountNumber`, `accountType`, `currency`), the account holder's name, and identifiers (`sub`, `userId`). The connector embeds these claims in the signed SD-JWT VC. * Standard SD-JWT VC claims (`iss`, `sub`, `iat`, `exp`, `vct`, `cnf`) are added automatically by the connector during credential signing. You don't need to include them in the request. * You store the `offer_id` because the connector uses it to correlate the callback with this specific offer. Without it, you cannot match incoming issuance results to the right customer session. #### Step 3: Display the credential offer[​](#step-3-display-the-credential-offer "Direct link to Step 3: Display the credential offer") Use `credential_offer_uri` to generate a QR code when the user is on a desktop. Use it as a deep link when the user is on a mobile device. The wallet app recognizes the `openid-credential-offer://` URI scheme and initiates the issuance flow. * cURL ```bash # Set the credential_offer_uri from the Step 2 response credential_offer_uri="openid-credential-offer://?credential_offer_uri=https%3A%2F%2Fissuer.example.com%2Foidc4vci%2Foffers%2Fabc123def456" # Cross-device: generate a QR code PNG from the URI (requires qrencode) qrencode -o qrcode.png "$credential_offer_uri" # Same-device: open the deep link directly (macOS) open "$credential_offer_uri" ``` After the user scans the QR code or taps the deep link, the wallet takes over. Behind the scenes, the wallet discovers the connector's metadata, exchanges the pre-authorized code for an access token (secured with [DPoP](/eudiw-connector/explanations/privacy-security/dpop.md)), requests a nonce, creates a key proof, and requests the credential. The connector signs the credential as an SD-JWT VC and delivers it to the wallet. You don't need to implement any of these protocol steps—the connector and wallet handle them automatically. #### Step 4: Implement the callback handler[​](#step-4-implement-the-callback-handler "Direct link to Step 4: Implement the callback handler") When the wallet completes the issuance flow, the connector delivers the result to your [callback](/eudiw-connector/explanations/architecture/connector-architecture.md) endpoint as an Issuance Event. This happens asynchronously—the connector calls your endpoint, not the other way around. The callback payload contains a `status` field that tells you the outcome. There are four possible statuses, and your code must handle all of them: | Status | What happened | Your response | | --------------- | --------------------------------------------------------------- | ------------------------------------------------- | | `OFFER_CREATED` | The offer was created and the session is active | Use for audit logging or to start a timeout timer | | `ISSUED` | The credential was successfully issued to the wallet | Update your records, confirm to the user | | `FAILED` | Issuance failed (the `errorDetails` field describes the reason) | Log the error, alert your team, offer retry | | `EXPIRED` | The session timed out before the wallet completed the flow | Create a new offer with a fresh QR code | Handle absent fields defensively The `errorDetails` field is only present when the status is `FAILED`. For `OFFER_CREATED`, `ISSUED`, and `EXPIRED`, this field is absent from the payload. Always check for its existence before accessing it. * cURL ```bash # Simulate an ISSUED callback for testing curl -X POST http://backend.example.com:3000/callback/issuance \ -H "Content-Type: application/json" \ -d '{ "eventId": "abc123def456", "status": "ISSUED", "offerId": "abc123def456" }' ``` Example `OFFER_CREATED` callback (informational, no action required): ```json { "eventId": "abc123def456", "status": "OFFER_CREATED", "offerId": "abc123def456" } ``` Example `FAILED` callback: ```json { "eventId": "abc123def456", "status": "FAILED", "offerId": "abc123def456", "errorDetails": "issuer service unavailable" } ``` Example `EXPIRED` callback: ```json { "eventId": "abc123def456", "status": "EXPIRED", "offerId": "abc123def456" } ``` The callback payload contains: | Field | Description | | -------------- | ------------------------------------------------------------------------------------------------------------------ | | `eventId` | Correlation key tied to the offer (same value as `offerId`). To deduplicate retries, combine `eventId` + `status`. | | `status` | One of `OFFER_CREATED`, `ISSUED`, `FAILED`, or `EXPIRED`. | | `offerId` | Correlation token matching the `offer_id` from Step 2. | | `errorDetails` | Present for `FAILED` status. Describes the failure reason. | Handle each status: * **OFFER\_CREATED**—the offer was created and the session is active. Use for audit logging or to start a timeout timer. No user-facing action is needed. * **ISSUED**—the credential was successfully issued to the wallet. Update your records accordingly (for example, mark the account as having an AOC issued). * **FAILED**—issuance failed. Check `errorDetails` for the reason, log the error, and consider offering the user a retry. * **EXPIRED**—the session time-to-live (TTL) expired before the wallet completed the flow. The default TTL is five minutes. Create a new offer if the user wants to try again. The connector delivers callbacks asynchronously (fire-and-forget). Always respond with HTTP 200 to acknowledge receipt. Keep your callback handler fast and offload heavy processing to a background queue if needed. For the complete list of payload fields and status descriptions, see the [callback events reference](/eudiw-connector/reference/callback-events.md). #### Step 5: Extend with tx\_code (optional)[​](#step-5-extend-with-tx_code-optional "Direct link to Step 5: Extend with tx_code (optional)") For higher-assurance issuance, you can add a transaction code to the offer. The transaction code is a one-time value (for example, a six-digit numeric code) that the user must enter in their wallet before the credential is issued. This adds an extra authorization layer—useful when regulatory requirements demand it or when the credential grants access to sensitive resources. To add a transaction code, include a `tx_code` object in the offer request. The connector returns a `tx_code_value` in the response that you deliver to the user via a separate channel (for example, SMS or email). The authorization server validates the code at the token endpoint before the wallet can proceed. * cURL ```bash curl -X POST http://connector.example.com:8081/offers \ -H "Content-Type: application/json" \ -d '{ "credential_configuration_id": "AccountOwnershipCredential", "claims": { "bankName": "Example Bank", "accountHolder": "Erika Mustermann", "accountNumber": "1234567890", "iban": "DE99370501981234567890", "bic": "COLSDE33XXX", "currency": "EUR", "accountType": "checking", "sub": "user-uuid-123", "userId": "user-uuid-123" }, "tx_code": { "input_mode": "numeric", "length": 6 } }' ``` Example response (HTTP 201 Created): ```json { "offer_id": "abc123def456", "credential_offer_uri": "openid-credential-offer://?credential_offer_uri=https%3A%2F%2Fissuer.example.com%2Foidc4vci%2Foffers%2Fabc123def456", "tx_code_value": "123456" } ``` The `tx_code` object contains: * `input_mode`—the type of input expected (for example, `"numeric"` for a numeric code) * `length`—the number of characters in the code (for example, `6`) * `description` (optional)—a human-readable description of the transaction code purpose (for example, `"Enter the code sent to your email"`) The response includes `tx_code_value` alongside the standard `offer_id` and `credential_offer_uri`. You are responsible for delivering this value to the user through a channel separate from the QR code or deep link. The wallet prompts the user to enter the code before proceeding with the token exchange. For more details on transaction code configuration and error handling, see [Use transaction codes](/eudiw-connector/how-to-guides/tx-code.md). #### How the issuance flow works[​](#how-the-issuance-flow-works "Direct link to How the issuance flow works") The following diagram shows the complete end-to-end flow between your backend, the connector, the authorization server, and the EUDI Wallet. Steps 1–6 correspond to your backend code. Steps 7–22 happen automatically between the wallet and the connector. The connector purges the credential claims from its session storage after the flow completes (whether the credential is issued, the flow fails, or the session expires). This [ephemeral data model](/eudiw-connector/explanations/privacy-security/ephemeral-data-model.md) means the connector does not retain sensitive claim data beyond the issuance session. #### Testing your integration[​](#testing-your-integration "Direct link to Testing your integration") ##### Start your backend service[​](#start-your-backend-service "Direct link to Start your backend service") Server setup Create a server entry point that combines the callback handler from Step 4 with a simple endpoint to trigger new issuance flows: 1. Add a `GET /start-issuance` route that calls the offer creation function from Step 2, generates a QR code from the `credential_offer_uri`, and renders an HTML page with the QR code and a deep link button. 2. Start the server on port 3000 (TypeScript) or 8080 (Java). 3. Open `http://localhost:3000/start-issuance` or `http://localhost:8080/start-issuance` in your browser to test. ##### Walk through the flow[​](#walk-through-the-flow "Direct link to Walk through the flow") 1. Start your backend service and open `http://localhost:3000/start-issuance` in your browser. 2. You see a QR code on the page. Open your test EUDI Wallet app and scan the QR code. 3. The wallet discovers the connector's metadata, exchanges the pre-authorized code for an access token, and requests the credential. 4. After the wallet receives the credential, the connector delivers a callback to your endpoint. 5. Check your server logs. You should see a log entry confirming the issuance with the customer ID. ##### Test error scenarios[​](#test-error-scenarios "Direct link to Test error scenarios") * **Let the session expire**: Create a credential offer but do not scan the QR code. After the session TTL passes (default five minutes), your callback receives an `EXPIRED` status. * **Simulate a failure**: Send a test callback with `"status": "FAILED"` and an `errorDetails` value to verify your error handling logic. * **Test with tx\_code**: Create an offer with `tx_code` enabled, scan the QR code, and enter the code in the wallet. Verify that the issuance completes and your callback receives `ISSUED`. ##### Test checklist[​](#test-checklist "Direct link to Test checklist") * Credential offer creates and returns `offer_id` and `credential_offer_uri` * QR code renders from `credential_offer_uri` * Deep link opens the wallet on mobile * Callback receives the issuance event with `ISSUED` status * Callback correctly correlates `offerId` with the original session * Callback handles all four statuses (`OFFER_CREATED`, `ISSUED`, `FAILED`, `EXPIRED`) * \[ ] `FAILED` callback includes `errorDetails` * Expired sessions are handled gracefully * tx\_code flow returns `tx_code_value` in the offer response * tx\_code flow completes when the correct code is entered #### What you learned[​](#what-you-learned "Direct link to What you learned") In this tutorial, you built a complete AOC issuance flow using the EUDIW Connector. Here is what you covered: * **Credential offers**: You called the connector's management API to create a credential offer with AOC-specific claims and received a `credential_offer_uri` for the wallet. * **QR code and deep link delivery**: You rendered the offer URI as a QR code for cross-device flows and as a deep link for same-device flows. * **Callback-based delivery**: You implemented a callback endpoint that receives the issuance event asynchronously from the connector, rather than polling for results. * **Status handling**: You handled all four issuance outcomes (`OFFER_CREATED`, `ISSUED`, `FAILED`, `EXPIRED`) with appropriate responses for each. * **Transaction codes**: You extended the flow with `tx_code` for additional authorization, delivering the code via a separate channel. * **Protocol flow**: The entire flow is built on the [OID4VCI](/eudiw-connector/explanations/standards/oid4vci-protocol.md) protocol, which provides [DPoP](/eudiw-connector/explanations/privacy-security/dpop.md)-secured token exchanges, nonce-based replay prevention, and cryptographic key binding in the issued credential. #### Troubleshooting[​](#troubleshooting "Direct link to Troubleshooting") ##### `unknown_credential_configuration` error[​](#unknown_credential_configuration-error "Direct link to unknown_credential_configuration-error") The `credential_configuration_id` in your offer request doesn't match any configured credential type. Verify that your [Type Metadata is configured](/eudiw-connector/how-to-guides/credential-type-configuration.md) and that the `credential_configuration_id` matches a key in the connector's Credential Issuer Metadata. ##### `invalid_proof` error[​](#invalid_proof-error "Direct link to invalid_proof-error") The wallet's Key Proof JWT failed validation. This typically indicates a mismatch between the wallet's proof audience and the connector's expected value. Check the connector logs for details. ##### Offer expired before wallet completes[​](#offer-expired-before-wallet-completes "Direct link to Offer expired before wallet completes") The default session TTL is five minutes. If users consistently time out, guide them to scan the QR code promptly after it is displayed. ##### Callback not receiving events[​](#callback-not-receiving-events "Direct link to Callback not receiving events") The connector delivers callbacks asynchronously when the flow completes. Verify that your callback endpoint is reachable from the connector and returns a 2xx response promptly. #### Next steps[​](#next-steps "Direct link to Next steps") * [Implement AOC issuance](/eudiw-connector/how-to-guides/integration-scenarios/aoc-issuance.md)—a task-oriented reference for production-ready AOC issuance when you already know the concepts * [Issue a credential](/eudiw-connector/how-to-guides/credential-issuance.md)—generic credential issuance for any credential type * [Use transaction codes](/eudiw-connector/how-to-guides/tx-code.md)—detailed guide for transaction code configuration and error handling #### Further reading[​](#further-reading "Direct link to Further reading") * [AOC issuance use case](/eudiw-connector/explanations/use-cases/aoc-issuance.md)—business context and conceptual flow for Account Ownership Credentials * [OID4VCI protocol](/eudiw-connector/explanations/standards/oid4vci-protocol.md)—how the issuance protocol works * [Callback events](/eudiw-connector/reference/callback-events.md)—issuance event statuses and payload fields * [Error codes](/eudiw-connector/reference/error-codes.md)—wallet-facing HTTP error responses --- ### Build passwordless authentication In this tutorial, you build a passwordless authentication system using the Truvity EUDIW Connector. Instead of usernames and passwords, users prove their identity by presenting a credential from their EUDI Wallet with [key binding (device binding)](/eudiw-connector/explanations/privacy-security/key-binding.md)—a proof that the person presenting the credential is the same person it was issued to. No passwords to steal, no phishing attacks to worry about, and no credential databases to protect. This tutorial uses an example credential type called "Account Ownership Credential" (AOC) to demonstrate the pattern, but you can use any credential type that supports key binding. You learn how to: * Construct a [DCQL](/eudiw-connector/explanations/standards/dcql.md) query that enforces cryptographic holder binding * Call the connector's management API to create an authentication request * Verify key binding proof in the callback and extract a stable user identifier * Recognize returning users across sessions using the `kbKeyId` * Manage authenticated sessions tied to wallet credentials * Extend the flow to support same-device deep links Estimated time: 30–45 minutes. #### What you'll build[​](#what-youll-build "Direct link to What you'll build") You build a backend service with three main components: 1. A login endpoint that creates a presentation request for an Account Ownership Credential (AOC) with key binding enforcement, and displays a QR code for the user to scan. 2. A callback endpoint that receives the verification result, verifies the key binding proof, and extracts the `kbKeyId`—a stable, privacy-preserving identifier derived from the user's wallet key. 3. A session management layer that binds the `kbKeyId` to a user record, recognizes returning users, and manages session lifecycle. The user experience looks like this: a customer visits your login page, scans a QR code with their EUDI Wallet, approves the authentication request, and your backend creates an authenticated session within seconds. When the same user returns, your system recognizes them by their `kbKeyId` without asking for any credentials again—just scan and go. Prerequisites * Completed the [verification quickstart](/eudiw-connector/getting-started/verify-credentials.md) (running connector with certificate and callback configured) * Node.js 18+ development environment (the setup steps use npm) * Basic understanding of the [EUDI Wallet ecosystem](/eudiw-connector/overview/ecosystem-context.md) * A credential in a test wallet that supports [key binding](/eudiw-connector/explanations/privacy-security/key-binding.md) #### Step 1: Set up your project[​](#step-1-set-up-your-project "Direct link to Step 1: Set up your project") Start by creating a new project and installing the dependencies you need. This project is similar to the [KYC tutorial](/eudiw-connector/tutorials/kyc-tutorial.md), but adds session management libraries because authentication requires tracking logged-in users across requests. * Shell ```bash mkdir passwordless-auth && cd passwordless-auth npm init -y npm install express axios qrcode express-session npm install -D @types/express @types/qrcode @types/express-session typescript ``` Here is what each dependency does: * **express / Spring Boot**: Hosts the callback endpoint and login pages. * **axios / OkHttp**: Calls the connector's management API to create authentication requests. * **qrcode / ZXing**: Generates QR codes from the connector's response URI so users can scan with their wallet. * **express-session / Spring Session**: Manages authenticated user sessions after successful login. In production, back this with a persistent store like Redis. You need two in-memory stores: one for tracking login attempts (correlating the connector's `state` with your login flow) and one for user records (mapping `kbKeyId` to user accounts). In production, both would be backed by a database. What to implement Your session store needs: * A `loginSessions` map keyed by the connector's `state` value, storing a `LoginSession` object with fields: `sessionId` (string), `state` (string), `status` (string—starts as `"pending"`), `kbKeyId` (optional string), `accountId` (optional string), and `createdAt` (timestamp). * A `userRecords` map keyed by `kbKeyId`, storing a `UserRecord` object with fields: `kbKeyId` (string), `accountId` (string), `displayName` (string), `firstSeenAt` (timestamp), `lastLoginAt` (timestamp), and `loginCount` (integer). * A `responseCodeMap` for same-device flow, mapping the connector's `responseCode` to the `state` value. #### Step 2: Create an authentication request[​](#step-2-create-an-authentication-request "Direct link to Step 2: Create an authentication request") Now you create a presentation request that asks the user's wallet for an Account Ownership Credential (AOC) with cryptographic key binding. This is the core of passwordless authentication—instead of checking a password, you verify that the user possesses the private key bound to their credential. An AOC is a credential that links a user's wallet to an account in your system. Think of it as a digital membership card: the credential itself proves the user has an account, and the key binding proof proves the person presenting it is the legitimate holder. AOC is an example credential type used in this tutorial—in production, you would define your own authentication credential type and VCT value. AOC issuance happens outside the connector's scope—typically during account creation, your system (or a trusted issuer) issues an AOC to the user's wallet. For this tutorial, you need an AOC already present in your test wallet. See [Authentication with EUDI Wallet](/eudiw-connector/explanations/use-cases/authentication.md) for how AOCs fit into the broader ecosystem. The key difference from the [KYC tutorial](/eudiw-connector/tutorials/kyc-tutorial.md) is the `require_cryptographic_holder_binding` field. This field defaults to `true` when omitted, so the connector requests a key binding proof by default. Setting it explicitly to `true` in the DCQL query makes the requirement visible in your code and ensures it is never accidentally removed. Here is what key binding means in plain terms: * The wallet signs the presentation with the user's private key. * The connector verifies this signature and includes the result in the callback. * You get a `kbKeyId`—an [RFC 7638](https://www.rfc-editor.org/rfc/rfc7638) [JWK Thumbprint](/eudiw-connector/reference/glossary.md) (a deterministic hash of the user's public key) that serves as a stable identifier for that user. * Because the private key never leaves the wallet, no one can impersonate the user, even if they somehow obtained a copy of the credential. The credential format stays `dc+sd-jwt`—key binding is controlled by the `require_cryptographic_holder_binding` field, not by the format string. Note that `require_cryptographic_holder_binding` is a connector API parameter, not part of the DCQL specification. The connector uses it to decide whether to request a [key binding](/eudiw-connector/explanations/privacy-security/key-binding.md) proof from the wallet when constructing the [OID4VP](/eudiw-connector/explanations/standards/oid4vp-protocol.md) authorization request. The field defaults to `true`, so the connector requests key binding even if you omit it. Setting it explicitly makes the intent clear in your code. Terminology: key binding vs. device binding The [SD-JWT VC](/eudiw-connector/explanations/credential-formats/sd-jwt.md) specification calls this mechanism "key binding." The Architecture Reference Framework (ARF) uses "device binding" as the primary term. This tutorial uses "key binding" to align with the connector API parameter name `require_cryptographic_holder_binding`. See [Key binding (device binding)](/eudiw-connector/explanations/privacy-security/key-binding.md) for a detailed explanation. * cURL ```bash curl -X POST http://connector:8081/oidc4vp \ -H "Content-Type: application/json" \ -d '{ "dcql_query": { "credentials": [ { "id": "aoc_auth", "format": "dc+sd-jwt", "meta": { "vct_values": ["urn:eudi:aoc:1"] }, "claims": [ { "path": ["account_id"] } ], "require_cryptographic_holder_binding": true } ] } }' ``` Example response: ```json { "state": "abc123", "same_device_request_uri": "openid4vp://?client_id=x509_hash%3A&request_uri=https%3A%2F%2Fconnector.example.com%2Foidc4vp%2Fabc123%2Frequest%3Fflow_type%3Dsame-device", "cross_device_request_uri": "openid4vp://?client_id=x509_hash%3A&request_uri=https%3A%2F%2Fconnector.example.com%2Foidc4vp%2Fabc123%2Frequest%3Fflow_type%3Dcross-device" } ``` Store the `state` value to correlate with the callback later. Both URIs use the `openid4vp://` scheme with `client_id` and `request_uri` query parameters — pass them to the wallet as-is without parsing. The `client_id` uses the `x509_hash` prefix followed by a hash of the connector's access certificate. Render `cross_device_request_uri` as a QR code or redirect the user to `same_device_request_uri` for same-device flows. Notice that the request body is simpler than the KYC tutorial—you only request the `account_id` claim because authentication does not need the user's full identity. You also skip `redirect_uri` for now (the connector uses sensible defaults). You add `redirect_uri` when you extend to same-device flow in Step 4. The most important line is `require_cryptographic_holder_binding: true`. Although the connector defaults this field to `true` when omitted, setting it explicitly documents the intent and prevents accidental removal. When key binding is turned off (set to `false`), the `kbKeyId` and `kbSignatureIsValid` fields are absent from the callback payload. For authentication, key binding is essential. Replay protection OID4VP includes a `nonce` parameter in every authorization request to prevent replay attacks. The connector generates this nonce automatically—you do not need to supply one. The wallet includes the nonce in its response, and the connector verifies it before delivering the callback. #### Step 3: Implement the callback endpoint[​](#step-3-implement-the-callback-endpoint "Direct link to Step 3: Implement the callback endpoint") When the user scans the QR code and approves the authentication request, the connector verifies the credential and the key binding proof, then delivers the result to your [callback](/eudiw-connector/explanations/architecture/connector-architecture.md) endpoint as a Presented Credentials Event. This is the same asynchronous pattern as the KYC tutorial, but with two additional fields that matter for authentication: `kbSignatureIsValid` and `kbKeyId`. Here is what these fields mean: * **`kbSignatureIsValid`**—a boolean that tells you whether the wallet successfully proved possession of the private key bound to the credential. If this is `true`, the person presenting the credential is the legitimate holder. If it is `false`, someone may have obtained a copy of the credential without the corresponding private key. Always check this field before granting access. * **`kbKeyId`**—an [RFC 7638](https://www.rfc-editor.org/rfc/rfc7638) [JWK Thumbprint](/eudiw-connector/reference/glossary.md) of the holder's public key. This is a deterministic hash computed from the key's mathematical parameters, so the same wallet presenting the same credential always produces the same `kbKeyId`. You use this as a stable user identifier—it does not change across sessions, and it does not reveal the actual public key. Your callback handler needs to: 1. Verify that `kbSignatureIsValid` is `true`—reject the login if it is not. 2. Extract the `kbKeyId` as the user identifier. 3. Extract the `account_id` claim for additional context. 4. Find or create a user record bound to the `kbKeyId`. 5. Handle all five statuses, just like in the KYC tutorial. Handle absent fields defensively The `credentials` and `credentialsRaw` fields are only present when the status is `FULFILLED`. For `REJECTED`, `EXPIRED`, `PROCESSING_ERROR`, and `VERIFICATION_FAILED`, these fields are absent from the payload. The `errorDetails` field is present only for `REJECTED`, `PROCESSING_ERROR`, and `VERIFICATION_FAILED`. * cURL ```bash # Simulate a FULFILLED callback with key binding for testing curl -X POST http://localhost:3000/callback/auth \ -H "Content-Type: application/json" \ -d '{ "status": "FULFILLED", "state": "abc123", "responseCode": "RESPONSE_CODE_abc123", "credentials": { "aoc_auth": [ { "issuer": "https://issuer.example.com", "claims": { "account_id": "acct_12345" }, "signatureIsValid": true, "supportRevocation": false, "supportTrustAnchor": true, "isTrusted": true, "isCertificateRevoked": false, "credentialCategory": "QEAA", "trustSource": "lotl", "supervisoryMemberState": "DE", "qualifiedStatus": true, "trustDataTimestamp": "2026-05-15T08:30:00Z", "kbKeyId": "JWK_THUMBPRINT_abc123", "kbSignatureIsValid": true } ] }, "credentialsRaw": { "aoc_auth": [ { "claims": "eyJhY2NvdW50X2lkIjoiYWNjdF8xMjM0NSJ9", "issuer": "https://issuer.example.com", "kbKeyId": "JWK_THUMBPRINT_abc123" } ] } }' ``` Trust verification fields The trust verification fields (`credentialCategory`, `trustSource`, `supervisoryMemberState`, `qualifiedStatus`, `trustDataTimestamp`) appear when the connector runs in LoTL-enabled mode with a configured trust list source. In static-only mode, these fields are absent and only `isTrusted` and `isCertificateRevoked` are present. See [Configure trust anchor verification](/eudiw-connector/how-to-guides/configure-trust-anchors.md) for configuring LoTL-driven trust verification. When testing with the mock wallet, the trust verification fields differ from the preceding production-realistic example. The mock wallet's test credentials are not issued by LoTL-registered issuers, so `isTrusted` is `false` and `trustSource` is `untrusted`. The example payload shows what you receive in production with a real LoTL-registered issuer. The enriched trust fields tell you about the issuer's standing in the EU trust framework: * `credentialCategory`—the legal-effect classification of the credential (PID, QEAA, PUB\_EAA, NON\_QUALIFIED\_EAA). See [LoTL trust verification](/eudiw-connector/explanations/trust-revocation/lotl-verification.md). * `trustSource`—where trust was resolved: `lotl` (EU trust hierarchy), `static` (configured anchor), or `untrusted`. * `supervisoryMemberState`—ISO 3166-1 alpha-2 code of the supervising Member State. * `qualifiedStatus`—whether the issuer holds a qualified trust service entry. * `trustDataTimestamp`—when the trust data snapshot used for this verification was obtained. The `credentialsRaw` field contains the same credential data without verification flags: `claims` as a base64-encoded JSON object, plus `issuer`, `validFrom`, `validUntil`, `kbKeyId`, and `transactionDataHashes`. Use `credentialsRaw` when you need the disclosed attributes in their raw encoded form for forwarding to another system or for audit purposes. See the [callback events reference](/eudiw-connector/reference/callback-events.md) for the complete list of callback statuses. The key difference from the KYC callback is the key binding verification block. In the KYC tutorial, you check `signatureIsValid` to confirm the credential is genuine. Here, you also check `kbSignatureIsValid` to confirm the presenter is the legitimate holder. This two-layer verification—credential authenticity plus holder binding—is what makes passwordless authentication secure. For the complete list of statuses and error codes, see the [callback events reference](/eudiw-connector/reference/callback-events.md). #### Step 4: Extend to same-device flow[​](#step-4-extend-to-same-device-flow "Direct link to Step 4: Extend to same-device flow") So far, your integration supports the cross-device flow where the user scans a QR code from a desktop browser. But what if the user is already on their mobile device? Scanning a QR code on the same device is awkward. For this scenario, you use the `same_device_request_uri` as a deep link that opens the wallet app directly. The same-device flow introduces one additional concept: the `responseCode`. In the cross-device flow, your backend learns the result through the callback alone. In the same-device flow, the user's browser also needs to know the result so it can display the right page. After the wallet completes the flow, it redirects the user's browser to your `redirect_uri` with a `response_code` query parameter. Your backend matches this `response_code` to the `responseCode` from the callback to look up the authentication result. Update the authentication function to return both URIs and include a `redirect_uri`: * cURL ```bash curl -X POST http://connector:8081/oidc4vp \ -H "Content-Type: application/json" \ -d '{ "dcql_query": { "credentials": [ { "id": "aoc_auth", "format": "dc+sd-jwt", "meta": { "vct_values": ["urn:eudi:aoc:1"] }, "claims": [ { "path": ["account_id"] } ], "require_cryptographic_holder_binding": true } ] }, "redirect_uri": "http://localhost:3000/auth-result" }' ``` Example response: ```json { "state": "abc123", "same_device_request_uri": "openid4vp://?client_id=x509_hash%3A&request_uri=https%3A%2F%2Fconnector.example.com%2Foidc4vp%2Fabc123%2Frequest%3Fflow_type%3Dsame-device", "cross_device_request_uri": "openid4vp://?client_id=x509_hash%3A&request_uri=https%3A%2F%2Fconnector.example.com%2Foidc4vp%2Fabc123%2Frequest%3Fflow_type%3Dcross-device" } ``` The response is the same as the cross-device request, but now the connector knows to redirect the user's browser to your `redirect_uri` with a `response_code` parameter after the wallet completes the flow. Now add a result endpoint that the browser hits after the wallet redirect. The connector only redirects the browser to your `redirect_uri` when the presentation succeeds (`FULFILLED` status in same-device flow). For `REJECTED`, `EXPIRED`, and `PROCESSING_ERROR`, the connector does not generate a `responseCode` and the browser is never redirected—your frontend must handle those cases separately (for example, by polling the login session status or displaying a timeout message after a delay). For `VERIFICATION_FAILED` caused by trust enforcement failures in same-device flow, the connector does include a `responseCode` because the wallet already redirected the browser—handle this case in your `/auth-result` endpoint alongside the success case. This `GET /auth-result` endpoint reads the `response_code` query parameter, looks up the corresponding login session via `findStateByResponseCode()`, and completes the login. What to implement Your auth-result endpoint needs: * A `GET /auth-result` route that reads the `response_code` query parameter from the browser redirect. * A lookup from `response_code` to the original `state` value using `findStateByResponseCode()`. * A lookup from `state` to the login session to check the authentication status. * Response logic: if the login session status is `"authenticated"`, set session cookies (`kbKeyId`, `accountId`) and display a success message. If the callback has not arrived yet (status still `"pending"`), display a brief loading state and retry. The browser only reaches this endpoint on success, so you do not need to handle `"declined"` or `"expired"` here—handle those in your frontend polling logic. * The response body can be HTML or plain text—the examples below use plain text for simplicity. Your frontend decides which flow to use based on the user's device. On desktop, display the QR code. On mobile, render the deep link as a button or redirect to it directly. Both flows use the same callback endpoint—the only difference is how the user initiates the interaction and how the browser learns the result. #### Step 5: Manage user sessions[​](#step-5-manage-user-sessions "Direct link to Step 5: Manage user sessions") With the callback handler authenticating users, you now need to manage their sessions. The `kbKeyId` is the anchor for your session management—it is the stable identifier that ties a browser session to a verified wallet holder. In a traditional password-based system, you store a hashed password and compare it on each login. With wallet-based authentication, the `kbKeyId` replaces the password hash. The first time a user authenticates, you create a user record keyed by `kbKeyId`. On subsequent logins, you look up the existing record and update the last login timestamp. The user never needs to remember anything—their wallet handles the cryptographic proof. What to implement Your session management layer needs: * A `requireAuth` middleware that checks for a valid `kbKeyId` in the session and enforces session expiry (for example, 24 hours). * A `createAuthenticatedSession` function that stores the `kbKeyId` and `accountId` in the session after successful callback verification. * A `destroySession` function for logout. Now add protected routes and a logout endpoint to your app. Create a `GET /dashboard` route guarded by `requireAuth` that displays the user's account ID and login count, and a `GET /logout` route that destroys the session. What to implement Your protected routes need: * A `GET /dashboard` route guarded by `requireAuth` middleware that displays the user's account ID, display name, login count, and last login timestamp. * A `GET /logout` route that destroys the session and redirects to the login page. A few things to keep in mind about session management: * The `kbKeyId` is stable as long as the user presents the same credential from the same wallet. If the user re-provisions their wallet or obtains a new credential, the `kbKeyId` changes. Your app should handle this gracefully—for example, by allowing users to link a new wallet key to their existing account through a re-verification flow. * In production, back your session store with Redis, a database, or another persistent store. The in-memory stores in this tutorial are for learning purposes only. * Set session expiry policies that match your security requirements. A 24-hour session is reasonable for many applications, but high-security scenarios may require shorter sessions or re-authentication for sensitive operations. #### Testing your integration[​](#testing-your-integration "Direct link to Testing your integration") Follow these steps to test the complete passwordless authentication flow end to end. ##### Start your backend service[​](#start-your-backend-service "Direct link to Start your backend service") * Shell ```bash npx ts-node src/server.ts ``` ##### Walk through the flow[​](#walk-through-the-flow "Direct link to Walk through the flow") 1. Start your backend service and open `http://localhost:3000/login` in your browser. 2. You see a QR code on the login page. Open your test EUDI Wallet app and scan the QR code. 3. The wallet displays a consent screen showing the requested credential (AOC) and the `account_id` attribute. Review and approve the request. 4. After approval, the wallet submits the credential with a key binding proof to the connector. The connector verifies both the credential and the key binding proof, then delivers the result to your callback endpoint. 5. Check your server logs. You should see either "New user registered" (first login) or "Returning user recognized" (subsequent logins) with the `kbKeyId` and login count. 6. Navigate to `http://localhost:3000/dashboard`. You should see your authenticated dashboard with the user's account ID and login count. ##### Test returning user recognition[​](#test-returning-user-recognition "Direct link to Test returning user recognition") 1. Log out by visiting `/logout`. 2. Go back to `/login` and scan the QR code again with the same wallet. 3. Check the server logs—you should see "Returning user recognized" with an incremented login count. The `kbKeyId` is the same as the first login because the same wallet key was used. ##### Test error scenarios[​](#test-error-scenarios "Direct link to Test error scenarios") * **Reject the request**: Scan the QR code but decline the consent screen in the wallet. Your callback receives a `REJECTED` status. * **Let the session expire**: Create an authentication request but do not scan the QR code. After the expiration time passes, your callback receives an `EXPIRED` status. * **Test same-device flow**: Open the `/login` page on a mobile device and tap the "Open in wallet" link. After completing the flow, the wallet redirects your browser to `/auth-result` with the `response_code` parameter. #### What you learned[​](#what-you-learned "Direct link to What you learned") In this tutorial, you built a complete passwordless authentication system using the EUDIW Connector. Here is what you covered: * **Key binding enforcement**: You used the connector API parameter `require_cryptographic_holder_binding: true` in the presentation request to explicitly require the wallet to prove possession of the credential's private key. The connector defaults this field to `true`, but setting it explicitly documents the intent and prevents credential theft and replay attacks. * **Holder binding verification**: You checked `kbSignatureIsValid` in the callback to confirm the wallet holder is the legitimate credential owner, and rejected authentication attempts where the proof failed. * **Stable user identifiers**: You extracted the `kbKeyId`—an [RFC 7638](https://www.rfc-editor.org/rfc/rfc7638) [JWK Thumbprint](/eudiw-connector/reference/glossary.md) of the holder's public key—and used it as a stable, privacy-preserving identifier to recognize returning users across sessions. * **Passwordless session management**: You bound the `kbKeyId` to user records and browser sessions, implementing a complete login flow without passwords, password hashes, or credential databases. * **Status handling**: You handled all five verification outcomes (`FULFILLED`, `REJECTED`, `EXPIRED`, `PROCESSING_ERROR`, `VERIFICATION_FAILED`) with appropriate responses for each. * **Same-device correlation**: You used the `responseCode` field to correlate the browser redirect with the callback result in same-device flows. * **Security properties**: the entire flow is built on the [OID4VP](/eudiw-connector/explanations/standards/oid4vp-protocol.md) protocol under the [HAIP](/eudiw-connector/explanations/standards/haip.md) profile, providing phishing resistance through signed authorization requests, encrypted credential delivery from wallet to Relying Party, and cryptographic proof of holder identity through key binding. #### Next steps[​](#next-steps "Direct link to Next steps") * [Build a KYC verification flow](/eudiw-connector/tutorials/kyc-tutorial.md)—learn how to verify customer identity using PID credentials with the same connector API * [Passwordless authentication how-to guide](/eudiw-connector/how-to-guides/integration-scenarios/passwordless-authentication.md)—a task-oriented reference for authentication integration when you already know the concepts * [Key binding explained](/eudiw-connector/explanations/privacy-security/key-binding.md)—deep dive into how holder binding works in the EUDI ecosystem * [Ephemeral data model](/eudiw-connector/explanations/privacy-security/ephemeral-data-model.md)—understand how the connector handles credential data without persistent storage #### Further reading[​](#further-reading "Direct link to Further reading") * [HAIP profile](/eudiw-connector/explanations/standards/haip.md)—the High Assurance Interoperability Profile that governs authentication flows * [Key binding](/eudiw-connector/explanations/privacy-security/key-binding.md)—how cryptographic holder binding works under the hood * [Connector architecture](/eudiw-connector/explanations/architecture/connector-architecture.md)—how the connector processes requests and delivers results * [Error codes](/eudiw-connector/reference/error-codes.md)—wallet-facing HTTP error responses * [Callback events](/eudiw-connector/reference/callback-events.md)—Presented Credentials Event statuses and payload fields --- ### Build a KYC verification flow In this tutorial, you build a complete identity verification flow using the Truvity EUDIW Connector. You start from an empty project, create a backend service that requests government-issued identity credentials from a user's EUDI Wallet, and process the verified data for [KYC](/eudiw-connector/reference/glossary.md) compliance. By the end, you have a working integration that handles the full lifecycle: requesting credentials, receiving verification results, handling errors, and integrating verified identity data into your app. You learn how to: * Construct a DCQL query to request specific identity attributes * Call the connector's management API to create a presentation request * Generate a QR code for cross-device wallet interaction * Implement a callback endpoint that processes all verification outcomes * Extract and validate verified identity data from PID credentials * Extend the flow to support same-device deep links Estimated time: 30–45 minutes. #### What you'll build[​](#what-youll-build "Direct link to What you'll build") You build a backend service with two main components: 1. A request endpoint that creates a presentation request for PID (Personal Identification Data) credentials and displays a QR code for the user to scan with their EUDI Wallet. 2. A callback endpoint that receives the verification result from the connector, extracts identity attributes (name, date of birth, address, nationality), validates the credential, and stores the verified data. The user experience looks like this: a customer visits your app, scans a QR code with their EUDI Wallet, selects the requested credential, approves sharing their identity data, and your backend receives the verified attributes within seconds. No document scans, no manual review—cryptographically verified government-issued identity data delivered directly to your app. Prerequisites * Completed the [verification quickstart](/eudiw-connector/getting-started/verify-credentials.md) (running connector with certificate and callback configured) * Node.js 18+ development environment (the setup steps use npm) * Basic understanding of the [EUDI Wallet ecosystem](/eudiw-connector/overview/ecosystem-context.md) #### Step 1: Set up your project[​](#step-1-set-up-your-project "Direct link to Step 1: Set up your project") Start by creating a new project and installing the dependencies you need. The project uses an HTTP framework for the callback endpoint, an HTTP client for calling the connector's API, and a QR code library for displaying the wallet request. * Shell ```bash mkdir kyc-verification && cd kyc-verification npm init -y npm install express axios qrcode npm install -D @types/express @types/qrcode typescript ``` Here is what each dependency does: * **express / Spring Boot**: Hosts the callback endpoint that receives verification results from the connector. * **axios / OkHttp**: Calls the connector's management API to create presentation requests. * **qrcode / ZXing**: Generates QR codes from the connector's response URI so users can scan with their wallet. You also need an in-memory store to track verification sessions. In production, you would use a database, but a simple map works for this tutorial. Session management Your integration needs an in-memory store to track verification sessions. In production, use a database, but a simple map works for this tutorial. Create a session store that maps the connector's `state` value to your app's session data (app ID, status, verified customer data). You use this store in the callback handler to correlate incoming results with the original request. #### Step 2: Create a presentation request[​](#step-2-create-a-presentation-request "Direct link to Step 2: Create a presentation request") Now you create a presentation request that tells the connector which credentials and attributes you need from the user's wallet. You use a [DCQL](/eudiw-connector/explanations/standards/dcql.md) (Digital Credentials Query Language) query to specify the exact attributes required for KYC verification. DCQL is the standard query language for requesting credentials in the EUDI Wallet ecosystem. Instead of asking for an entire credential, you specify exactly which claims (attributes) you need. This is called [selective disclosure](/eudiw-connector/explanations/privacy-security/selective-disclosure.md)—the wallet reveals only the requested attributes, nothing more. For KYC, you need five PID attributes: given name, family name, date of birth, address, and nationality. note The VCT values, requested claims, and credential values in this tutorial are examples for a typical KYC scenario. In production, request the attributes required by your regulatory obligations and available in the target [attestation scheme](/eudiw-connector/reference/glossary.md#eudi-wallet-ecosystem). Available attributes vary by issuer and member state. The request goes to `POST /oidc4vp` on the connector's management API (port 8081). The connector creates a signed authorization request and returns three values: * `state`—a correlation token you use to match the callback with this request * `cross_device_request_uri`—a URI to render as a QR code (for when the user is on a different device than their wallet) * `same_device_request_uri`—a deep link URI (for when the user is on the same device as their wallet) For now, you use only the `cross_device_request_uri` to generate a QR code. You add same-device support in Step 4. * cURL ```bash curl -X POST http://connector:8081/oidc4vp \ -H "Content-Type: application/json" \ -d '{ "dcql_query": { "credentials": [ { "id": "pid_kyc", "format": "dc+sd-jwt", "meta": { "vct_values": ["urn:eudi:pid:1"] }, "claims": [ { "path": ["given_name"] }, { "path": ["family_name"] }, { "path": ["birthdate"] }, { "path": ["address"] }, { "path": ["nationalities"] } ] } ] }, "expires_in": 600, "redirect_uri": "http://localhost:3000/verification-result" }' ``` Example response: ```json { "state": "abc123", "same_device_request_uri": "openid4vp://?client_id=x509_hash%3A&request_uri=https%3A%2F%2Fconnector.example.com%2Foidc4vp%2Fabc123%2Frequest%3Fflow_type%3Dsame-device", "cross_device_request_uri": "openid4vp://?client_id=x509_hash%3A&request_uri=https%3A%2F%2Fconnector.example.com%2Foidc4vp%2Fabc123%2Frequest%3Fflow_type%3Dcross-device" } ``` The two URIs share the same structure but differ in the `flow_type` query parameter (`same-device` vs `cross-device`). Each URI includes a `client_id` derived from your X.509 access certificate hash and a `request_uri` pointing to the connector's public endpoint. The `redirect_uri` parameter is optional. It tells the wallet where to redirect the user's browser after the same-device flow completes. Omit it for cross-device-only flows. You use it in Step 4. Store the `state` value to correlate with the callback later. Render `cross_device_request_uri` as a QR code or redirect the user to `same_device_request_uri` for same-device flows. A few things to notice in this code: * The `id` field (`"pid_kyc"`) is your own identifier for this credential in the query. You use it later in the callback to look up the presented credential. * The `format` is `dc+sd-jwt`, which is the standard format for PID credentials in the EUDI Wallet ecosystem. It supports selective disclosure, meaning the wallet only reveals the claims you request. * The `claims` array lists exactly which attributes you need. The wallet shows the user which data is being requested and asks for consent before sharing. * The connector validates the `vct` (Verifiable Credential Type) claim in the presented credential against the `vct_values` you specified in the query before delivering the callback. If the credential type does not match, the connector rejects it and you receive a `VERIFICATION_FAILED` status. * The `expires_in` field controls how long the QR code remains valid, in seconds. Set it long enough for the user to scan, but short enough to limit the window for misuse. * You store the `state` value because the connector uses it to correlate the callback with this specific request. Without it, you cannot match incoming verification results to the right user session. #### Step 3: Implement the callback endpoint[​](#step-3-implement-the-callback-endpoint "Direct link to Step 3: Implement the callback endpoint") When the user scans the QR code and approves the credential presentation in their wallet, the connector verifies the credential and delivers the result to your [callback](/eudiw-connector/explanations/architecture/connector-architecture.md) endpoint as a `PresentedCredentialsEvent`. This happens asynchronously—the connector calls your endpoint, not the other way around. The callback payload contains a `status` field that tells you the outcome. There are five possible statuses, and your code must handle all of them: | Status | What happened | Your response | | --------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------- | | `FULFILLED` | The user approved and the credential is verified | Extract and process the identity data | | `REJECTED` | The user declined the request in their wallet (the `errorDetails` field contains the wallet's OAuth 2.0 error code and optional description, for example `access_denied` or `access_denied: User canceled`) | Log the error, inform the user, and offer to retry | | `EXPIRED` | The session timed out before the user responded | Create a new request with a fresh QR code | | `PROCESSING_ERROR` | An internal error occurred (decryption, infrastructure) | Log the error, alert your team, offer retry | | `VERIFICATION_FAILED` | The credential failed verification (invalid signature, revoked, DCQL mismatch) | Log the error, deny access | Handle absent fields defensively The `credentials` and `credentialsRaw` fields are only present when the status is `FULFILLED`. For `REJECTED`, `EXPIRED`, `PROCESSING_ERROR`, and `VERIFICATION_FAILED`, these fields are absent from the payload. Always check for their existence before accessing them. The `errorDetails` field is present only for `REJECTED`, `PROCESSING_ERROR`, and `VERIFICATION_FAILED`. The `credentials` field contains verified and parsed credential data (claims as native objects, plus verification flags like `signatureIsValid` and `supportRevocation`). The `credentialsRaw` field contains the same credential data without verification flags: `claims` as a base64-encoded JSON object, plus `issuer`, `validFrom`, `validUntil`, `kbKeyId`, and `transactionDataHashes`. Use `credentialsRaw` when you need the disclosed attributes in their raw encoded form for forwarding to another system or for audit purposes. * cURL ```bash # Simulate a FULFILLED callback for testing curl -X POST https://example.com:3000/callback/kyc \ -H "Content-Type: application/json" \ -d '{ "status": "FULFILLED", "state": "abc123", "responseCode": "resp_xyz789", "credentials": { "pid_kyc": [ { "issuer": "https://pid-provider.example.com", "claims": { "given_name": "Erika", "family_name": "Mustermann", "birthdate": "1964-08-12", "address": { "street_address": "Heidestraße 17", "house_number": "17", "locality": "Berlin", "postal_code": "10557", "region": "Berlin", "country": "DE" }, "nationalities": ["DE"] }, "signatureIsValid": true, "supportRevocation": false, "supportTrustAnchor": true, "isTrusted": true, "isCertificateRevoked": false, "credentialCategory": "PID", "trustSource": "lotl", "supervisoryMemberState": "DE", "qualifiedStatus": false, "trustDataTimestamp": "2026-05-15T08:30:00Z", "kbKeyId": "", "kbSignatureIsValid": true } ] }, "credentialsRaw": { "pid_kyc": [ { "claims": "", "issuer": "https://pid-provider.example.com", "kbKeyId": "" } ] } }' ``` The `responseCode` field is used in same-device flows to correlate the browser redirect with this callback (covered in Step 4). It is only present in same-device flows — for cross-device flows, this field is absent from the payload. The `kbSignatureIsValid` field confirms the presenter holds the private key bound to the credential, proving they are the legitimate holder. See [key binding](/eudiw-connector/explanations/privacy-security/key-binding.md) for details. Trust verification fields The trust verification fields (`credentialCategory`, `trustSource`, `supervisoryMemberState`, `qualifiedStatus`, `trustDataTimestamp`) appear when the connector runs in LoTL-enabled mode with a configured trust list source. In static-only mode, these fields are absent and only `isTrusted` and `isCertificateRevoked` are present. See [Configure trust anchor verification](/eudiw-connector/how-to-guides/configure-trust-anchors.md) for configuring LoTL-driven trust verification. When testing with the mock wallet, the trust verification fields will differ from the production-realistic example above. The mock wallet's test credentials are not issued by LoTL-registered issuers, so `isTrusted` will be `false` and `trustSource` will be `untrusted`. The example payload shows what you receive in production with a real LoTL-registered issuer. The enriched trust fields tell you about the issuer's standing in the EU trust framework: * `credentialCategory`—the legal-effect classification of the credential (PID, QEAA, PUB\_EAA, NON\_QUALIFIED\_EAA). See [LoTL trust verification](/eudiw-connector/explanations/trust-revocation/lotl-verification.md). * `trustSource`—where trust was resolved: `lotl` (EU trust hierarchy), `static` (configured anchor), or `untrusted`. * `supervisoryMemberState`—ISO 3166-1 alpha-2 code of the supervising Member State. * `qualifiedStatus`—whether the issuer holds a qualified trust service entry. * `trustDataTimestamp`—when the trust data snapshot used for this verification was obtained. For the full field reference, see [Callback events](/eudiw-connector/reference/callback-events.md). A few important details about the callback: * The `credentials` field is a map where the key is the DCQL credential ID you specified in Step 2 (`"pid_kyc"`), and the value is an array of presented credentials. For a single-credential query like this one, the array typically contains one entry. * The fields `isRevoked`, `isTrusted`, `isCertificateRevoked`, `validFrom`, and `validUntil` are optional. The `isRevoked` field is only present when `supportRevocation` is `true`. The `isTrusted` and `isCertificateRevoked` fields are only present when `supportTrustAnchor` is `true`. Always check the `support*` flags before reading the dependent fields. * The `kbSignatureIsValid` field confirms [key binding](/eudiw-connector/explanations/privacy-security/key-binding.md). It proves the person presenting the credential holds the private key bound to it, preventing credential replay by a third party. Check this field alongside `signatureIsValid` for full cryptographic validation. * The callback may also include `transactionDataHashes` when [transaction data binding](/eudiw-connector/how-to-guides/transactional-data.md) is used. This field is not relevant for basic KYC flows. * The connector delivers the callback synchronously with a default two-second timeout and one retry. These defaults are configurable in the connector configuration. Keep your callback handler fast and offload heavy processing to an asynchronous queue if needed. * Always respond with HTTP 200 to acknowledge receipt. If your endpoint is unavailable or too slow, the wallet user sees an error on their device. Credential verification fields The simulated callback includes several credential verification fields beyond `signatureIsValid` and `kbSignatureIsValid`: * **`supportRevocation`**—whether the credential includes a Status List Token for revocation checking. When `true`, the `isRevoked` field indicates the revocation status. * **`supportTrustAnchor`**—whether the credential was signed with an X.509 certificate chain (`x5c` header). When `true`, the `isTrusted` and `isCertificateRevoked` fields are also present. * **`isTrusted`**—whether the chain terminated at a configured trust anchor and the last certificate's signature was verified against it. Only present when `supportTrustAnchor` is `true`. * **`isCertificateRevoked`**—whether any certificate in the issuer's X.509 chain was found on a Certificate Revocation List. Only present when `supportTrustAnchor` is `true`. See [Revocation mechanisms](/eudiw-connector/explanations/trust-revocation/revocation-mechanisms.md) for details. For the complete list of statuses and error codes, see the [callback events reference](/eudiw-connector/reference/callback-events.md). #### Step 4: Extend to same-device flow[​](#step-4-extend-to-same-device-flow "Direct link to Step 4: Extend to same-device flow") So far, your integration supports the cross-device flow where the user scans a QR code from a desktop browser. But what if the user is already on their mobile device? Scanning a QR code on the same device is awkward. For this scenario, you use the `same_device_request_uri` as a deep link that opens the wallet app directly. The same-device flow introduces one additional concept: the `responseCode`. In the cross-device flow, your backend learns the result through the callback alone. In the same-device flow, the user's browser also needs to know the result so it can display the right page. After the wallet completes the flow, it redirects the user's browser to your `redirect_uri` with a `response_code` query parameter. Your backend matches this `response_code` to the `responseCode` from the callback to look up the verification result. * cURL ```bash curl -X POST http://connector:8081/oidc4vp \ -H "Content-Type: application/json" \ -d '{ "dcql_query": { "credentials": [ { "id": "pid_kyc", "format": "dc+sd-jwt", "meta": { "vct_values": ["urn:eudi:pid:1"] }, "claims": [ { "path": ["given_name"] }, { "path": ["family_name"] }, { "path": ["birthdate"] }, { "path": ["address"] }, { "path": ["nationalities"] } ] } ] }, "expires_in": 600, "redirect_uri": "http://localhost:3000/verification-result" }' ``` Example response: ```json { "state": "abc123", "same_device_request_uri": "openid4vp://?client_id=x509_hash%3A&request_uri=https%3A%2F%2Fconnector.example.com%2Foidc4vp%2Fabc123%2Frequest%3Fflow_type%3Dsame-device", "cross_device_request_uri": "openid4vp://?client_id=x509_hash%3A&request_uri=https%3A%2F%2Fconnector.example.com%2Foidc4vp%2Fabc123%2Frequest%3Fflow_type%3Dcross-device" } ``` The response is the same as Step 2. Use `same_device_request_uri` as a deep link for mobile users, and `cross_device_request_uri` as a QR code for desktop users. To complete the same-device flow, your callback handler and your frontend need two additions: Callback handler update 1. In your callback handler, store the `responseCode` from the callback payload in a map keyed by `responseCode` → `state`. Add this after the status switch statement: if the event contains a `responseCode`, save the mapping so you can look it up later. 2. Add a `GET /verification-result` endpoint that accepts a `response_code` query parameter. This endpoint looks up the `state` from the response code map, finds the session, and displays the result to the user. The wallet redirects the user's browser to your `redirect_uri` with `?response_code=` after the flow completes. Your frontend decides which flow to use based on the user's device. On desktop, display the QR code. On mobile, render the deep link as a button or redirect to it directly. Both flows use the same callback endpoint—the only difference is how the user initiates the interaction and how the browser learns the result. Cross-device wallet response In cross-device flows, the connector returns an empty JSON object (`{}`) to the wallet after processing the response, per the [OID4VP](/eudiw-connector/explanations/standards/oid4vp-protocol.md) specification. Your backend learns the result exclusively through the callback. #### Step 5: Integrate verified data[​](#step-5-integrate-verified-data "Direct link to Step 5: Integrate verified data") With the callback handler in place, you now have verified identity data flowing into your app. The final step is mapping the PID claims to your app's data model and storing them appropriately. The PID credential provides standardized identity attributes. Map these to your own data structures for use in your KYC workflow, account creation, or compliance records. Data mapping Map the PID claims from the callback to your app's data model: 1. Access the credential using your DCQL credential ID (`"pid_kyc"`) as the key in the `credentials` map. 2. Extract the claims you requested: `given_name`, `family_name`, `birthdate`, `address`, and `nationalities` from the `claims` object. 3. Store the extracted data in your database alongside the verification timestamp and the `issuer` value for audit purposes. 4. In production, apply your data retention and access control policies to this data. Data handling responsibility You are responsible for applying your own data retention and access control policies to credential data received through callbacks. The connector does not persist credential data after delivering the callback. Consider your regulatory obligations (GDPR, sector-specific rules) when deciding how long to store verified identity data and who can access it. #### Testing your integration[​](#testing-your-integration "Direct link to Testing your integration") Follow these steps to test the complete KYC verification flow end to end. ##### Start your backend service[​](#start-your-backend-service "Direct link to Start your backend service") Server setup Create a server entry point that combines the callback handler from Step 3 with a simple endpoint to trigger new verifications: 1. Add a `GET /start-kyc` route that calls the presentation request function from Step 2, generates a QR code from the `cross_device_request_uri`, and renders an HTML page with the QR code and a deep link button using the `same_device_request_uri`. 2. Start the server on port 3000 (TypeScript) or 8080 (Java). 3. Open `http://localhost:3000/start-kyc` or `http://localhost:8080/start-kyc` in your browser to test. ##### Walk through the flow[​](#walk-through-the-flow "Direct link to Walk through the flow") 1. Start your backend service and open `http://localhost:3000/start-kyc` (TypeScript) or `http://localhost:8080/start-kyc` (Java) in your browser. 2. You see a QR code on the page. Open your test EUDI Wallet app and scan the QR code. 3. The wallet displays a consent screen showing the requested attributes: given name, family name, date of birth, address, and nationality. Review and approve the request. 4. After approval, the wallet submits the credential to the connector. The connector verifies the credential and delivers the result to your callback endpoint. 5. Check your server logs. You should see a log entry confirming the verification with the user's name and the credential issuer. ##### Test error scenarios[​](#test-error-scenarios "Direct link to Test error scenarios") * **Reject the request**: Scan the QR code but decline the consent screen in the wallet. Your callback receives a `REJECTED` status. * **Let the session expire**: Create a presentation request but do not scan the QR code. After the `expires_in` duration passes, your callback receives an `EXPIRED` status. * **Test same-device flow**: Open the `/start-kyc` page on a mobile device and tap the "Open in wallet" link. After completing the flow, the wallet redirects your browser to `/verification-result` with the `response_code` parameter. #### What you learned[​](#what-you-learned "Direct link to What you learned") In this tutorial, you built a complete KYC verification flow using the EUDIW Connector. Here is what you covered: * **DCQL queries**: You constructed a query that requests specific PID attributes using the [DCQL](/eudiw-connector/explanations/standards/dcql.md) query language, specifying the credential format, type, and individual claims. * **Presentation requests**: You called the connector's management API to create a presentation request and received URIs for both cross-device (QR code) and same-device (deep link) flows. * **Callback-based delivery**: You implemented a callback endpoint that receives the `PresentedCredentialsEvent` asynchronously from the connector, rather than polling for results. * **Credential validation**: You checked the cryptographic properties of the presented credential (`signatureIsValid`, `kbSignatureIsValid`) and used the `supportRevocation` and `supportTrustAnchor` flags to safely read conditional fields. * **Status handling**: You handled all five verification outcomes (`FULFILLED`, `REJECTED`, `EXPIRED`, `PROCESSING_ERROR`, `VERIFICATION_FAILED`) with appropriate responses for each. * **Same-device correlation**: You used the `responseCode` field to correlate the browser redirect with the callback result in same-device flows. * **Security properties**: The entire flow is built on the [OID4VP](/eudiw-connector/explanations/standards/oid4vp-protocol.md) protocol, which provides encrypted credential transmission, signed authorization requests, and cryptographic verification of credential authenticity. #### Next steps[​](#next-steps "Direct link to Next steps") * [Build passwordless authentication](/eudiw-connector/tutorials/auth-tutorial.md)—learn how to replace passwords with cryptographic key binding using the same connector API * [KYC verification how-to guide](/eudiw-connector/how-to-guides/integration-scenarios/kyc-verification.md)—a task-oriented reference for KYC integration when you already know the concepts * [Use transactional data](/eudiw-connector/how-to-guides/transactional-data.md)—bind contextual data to presentation requests for audit trails and consent proof * [Handle verification errors](/eudiw-connector/how-to-guides/error-handling.md)—implement robust error handling patterns for production deployments #### Further reading[​](#further-reading "Direct link to Further reading") * [DCQL query language](/eudiw-connector/explanations/standards/dcql.md)—how to specify credential requirements and attribute selection * [Connector architecture](/eudiw-connector/explanations/architecture/connector-architecture.md)—how the connector processes requests and delivers results * [Error codes](/eudiw-connector/reference/error-codes.md)—wallet-facing HTTP error responses * [Callback events](/eudiw-connector/reference/callback-events.md)—Presented Credentials Event statuses and payload fields * [Manage certificates](/eudiw-connector/how-to-guides/certificates.md)—configure X.509 access certificates for production use --- ## Ssi ### SSI Platform overview Welcome to the **Truvity SSI Platform** documentation. The SSI Platform provides a comprehensive suite of tools and services for building Self-Sovereign Identity (SSI) solutions, enabling organizations to manage digital identities, verifiable credentials, and secure credential exchange. #### What is the SSI Platform?[​](#what-is-the-ssi-platform "Direct link to What is the SSI Platform?") Truvity redefines how people establish trust, making it instantaneous and reliable. The internet lacks a foundational trust layer, which creates obstacles to building relationships and doing business. Trust drives everyday life. It supports business and social interactions, enables people to build connections, and helps them achieve shared goals. To accomplish this, Truvity leverages and expands upon the [trust triangle concept](/ssi/overview/core-concepts/triangle-of-trust.md), adapting it to the digital world. This entails adopting established industry standards such as [Decentralized Identifiers (DIDs)](/ssi/overview/core-concepts/decentralized-identifiers.md), [digital wallets](/ssi/overview/core-concepts/digital-wallets.md), [verifiable credentials (VCs)](/ssi/overview/core-concepts/verifiable-credentials.md), [verifiable presentations (VPs)](/ssi/overview/core-concepts/verifiable-presentations.md), and [credential schemas](/ssi/overview/core-concepts/credential-schemas.md) for individuals and businesses. These components work together to establish, preserve, and build trust within the digital landscape. From a technical standpoint, the Truvity Platform offers API endpoints and SDKs designed to facilitate the management of Decentralized Identifiers (DIDs), credentials, schemas, connections, and exchanges between various parties. These functionalities adhere to the principles of Self-Sovereign Identity (SSI) standards, ultimately empowering businesses with the capability for seamless interoperability. #### Key capabilities[​](#key-capabilities "Direct link to Key capabilities") The SSI Platform provides key features to improve the management and security of digital identities and credentials: ##### APIs and SDKs[​](#apis-and-sdks "Direct link to APIs and SDKs") Access comprehensive [APIs](/ssi/api-reference.md) and [SDKs](/ssi/sdk.md) to manage the full credential lifecycle and secure credential exchange between parties. ##### Credential schemas[​](#credential-schemas "Direct link to Credential schemas") Define, version, and publish reusable [credential schemas](/ssi/schemas.md) to ensure consistent, machine-readable structures for credentials across your organization and with external partners. Schemas maintain semantic meaning for older credentials while supporting new schema versions for evolving requirements. ##### User-defined types (UDTs)[​](#user-defined-types-udts "Direct link to User-defined types (UDTs)") Use language-specific [UDTs](/ssi/sdk/credential-lifecycle/user-defined-types.md) to define credential claims in your app code. UDTs provide strong type safety, detect potential errors at compile time, and simplify issuing and validating credentials directly through the SDK. ##### Labels and faceted search[​](#labels-and-faceted-search "Direct link to Labels and faceted search") [Attach labels and annotations](/ssi/sdk/manage-data/model-with-labels.md) to REST resources to improve searchability. Use the [faceted search capability](/ssi/sdk/manage-data/use-faceted-search.md) to efficiently filter and retrieve relevant results. ##### Linking files and credentials[​](#linking-files-and-credentials "Direct link to Linking files and credentials") [Link binary files](/ssi/sdk/linked-data/link-files.md) to credentials to support richer data representations. Create hierarchical relationships between drafts and credentials by [linking them](/ssi/sdk/linked-data/link-credentials.md). #### Get started[​](#get-started "Direct link to Get started") ##### New to SSI Platform?[​](#new-to-ssi-platform "Direct link to New to SSI Platform?") 1. **Start with the Overview** - Learn the [core concepts](/ssi/overview/core-concepts/verifiable-credentials.md) of Self-Sovereign Identity, verifiable credentials, and how the platform works 2. **Explore the SDK** - Follow the [Quick Start guide](/ssi/sdk/getting-started/quick-start.md) to integrate the Truvity SDK into your app 3. **Understand Schemas** - Learn how to [define and manage credential schemas](/ssi/schemas/core-concepts/meta-schema-model.md) for data consistency ##### Quick links[​](#quick-links "Direct link to Quick links") * **[Truvity SDK](/ssi/sdk.md)** - SDK documentation for integrating SSI capabilities into your apps * **[Credential Schemas](/ssi/schemas.md)** - Manage credential schemas for data consistency and interoperability * **[API Reference](/ssi/api-reference.md)** - Complete API documentation for programmatic access * **[Core Concepts](/ssi/overview/core-concepts/verifiable-credentials.md)** - Deep dive into SSI concepts and standards --- ### Truvity Platform API. (0.40.11) Search... * API Key * postCreate a new API key. * postSearch for API Keys. * delDelete API Key. * getGet the latest version of API Key. * patchUpdate annotations. * patchUpdate labels. * postRestore API Key. * getRead API Key's history. * getRead the specific version of the API Key. * Credential * postImport Credential. * postSearch for Credentials. * postUpload Credential's blob. * delDelete Credential. * getGet the latest version of Credential. * patchUpdate annotations. * patchUpdate labels. * postRestore Credential. * getRead Credential's history. * getRead the specific version of the Credential. * getDownload of Credential's blob. * getGet Credential Claim Values. * getVerify Credential. * Desk * getGet JSON Schema by slug and version. * ExperimentalgetGet Meta Schema by slug and version. * getGet VCDM JSON Schema by slug and version. * getGet JSON-LD Vocab by slug and version. * getGet DID-Document. * postReceive DIDComm Message. * DIDComm Message * postSearch for DIDComm Messages. * postSend a DIDComm Message. * delDelete DIDComm Message. * getGet the latest version of DIDComm Message. * patchUpdate annotations. * patchUpdate labels. * postRestore DIDComm Message. * getRead DIDComm Message's history. * getRead the specific version of the DIDComm Message. * DIDs * getReturn the tenant's DID(did:web) document. * Draft * postCreate Draft. * postSearch for Drafts. * delDelete Draft. * getGet the latest version of Draft. * patchUpdate Draft. * patchUpdate annotations. * patchIssue a Verifiable Credential from Draft. * patchUpdate labels. * postRestore Draft. * getRead Draft's history. * getRead the specific version of the Draft. * postExport Draft. * File * postCreate File. * postSearch for Files. * postUpload File's blob. * delDelete File. * getGet the latest version of File. * patchUpdate annotations. * patchUpdate labels. * postRestore File. * getRead File's history. * getRead the specific version of the File. * getDownload of File's blob. * GDPR * postCreate a request to support. * Key * postGenerate a new cryptographic key pair. * postImport a cryptographic key pair * postSearch for Keys. * delDelete Key. * getGet the latest version of Key. * patchUpdate annotations. * postSign an unsigned Credential. * postSign DIDComm Message Plaintext. * patchUpdate labels. * postSign an unsigned Presentation. * postRestore Key. * getRead Key's history. * getRead the specific version of the Key. * Presentation * postExport Presentation. * postImport Presentation. * postIssue Presentation. * postSearch for Presentations. * postUpload Presentation's blob. * delDelete Presentation. * getGet the latest version of Presentation. * patchUpdate annotations. * patchUpdate labels. * postRestore Presentation. * getRead Presentation's history. * getRead the specific version of the Presentation. * getDownload of Presentation's blob. * getVerify Presentation. * Published Credential Schema * postSearch for PublishedSchemas. * delDelete PublishedSchema. * getGet the latest version of PublishedSchema. * patchUpdate annotations. * patchUpdate labels. * postRestore PublishedSchema. * getRead the specific version of the PublishedSchema. * Credential Schema * postCreate Schema. * postImport Credential Schema. * postSearch for Schemas. * delDelete Schema. * getGet the latest version of Schema. * patchUpdate Schema. * patchUpdate annotations. * patchUpdate labels. * patchPublish Credential Schema. * postRestore Schema. * getRead Schema's history. * getRead the specific version of the Schema. [API docs by Redocly](https://redocly.com/redoc/) Download OpenAPI specification:[Download](https://openapi.truvity.com/sdk.yaml) Truvity Team : URL: License: [MIT](https://opensource.org/license/mit/) [Terms of Service](https://www.truvity.com/terms) Truvity Platform API. #### [](#tag/api-keys)API Key The API to manage Truvity API's keys. #### [](#tag/api-keys/operation/ApiKeyCreate)Create a new API key. Create a new API key resource. ###### Authorizations: *ApiKey* ###### header Parameters | | | | --------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Idempotency-Key | string\[ 32 .. 256 ] characters\[a-zA-Z0-9-]{32,256}From [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **Idempotency-Key** is a free identifier created by the client to identify a request. It is used by the service to identify repeated request to ensure idempotent behavior by sending the same (or a similar) response without executing the request a second time.Clients should be careful as any subsequent requests with the same key may return the same response without further check. Thus, it is recommended to use a UUID version 4 (random) or any other random string with enough entropy to avoid collisions.Keys expire after 24 hours. Clients are responsible to stay within this limit, if they require idempotent behavior.See [API Guideline Rule #181](https://opensource.zalando.com/restful-api-guidelines/#230) for further details. | ###### Request Body schema: application/jsonrequired | | | | ----------- | -------------------------------------- | | annotations | objectThe annotations of the resource. | | labels | objectThe labels of the resource. | ##### Responses **201** The created API key resource. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **415** The schema represents an HTTP "Unsupported Media Type" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. post/api-keys URL for header-protected customer communication. https://api.truvity.{zone}/api-keys URL for cookie-protected customer communication. https://docs.truvity.com/api/api-keys ##### Request samples * Payload * Go * Java * TypeScript Content type application/json Copy Expand all Collapse all `{ "annotations": { "property1": "string", "property2": "string" }, "labels": { "property1": "string", "property2": "string" } }` ##### Response samples * 201 * 400 * 401 * 403 * 415 * 429 * 500 * default Content type application/vnd.truvity.api-key+json;version=1 Copy Expand all Collapse all `{ "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "expiration": "2019-08-24T14:15:22Z", "secret": "pa$$word", "subject_id": "80e197be-61ad-4068-b4ff-a483fb5c18f9" }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 }` #### [](#tag/api-keys/operation/ApiKeySearch)Search for API Keys. Search for API Keys with extended filters capabilities. ###### Authorizations: *ApiKey* ###### Request Body schema: application/jsonrequired | | | | ------ | ------------------------------------------------------------------------------------------------------------- | | filter | Array of objects (ApiKeyFilter)<= 4 itemsThe filter to apply to the search. | | sort | Array of objects (ApiKeySort)<= 4 itemsThe sort order to apply to the search. | ##### Responses **200** The search results of API Key. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **415** The schema represents an HTTP "Unsupported Media Type" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. post/api-keys/search URL for header-protected customer communication. https://api.truvity.{zone}/api-keys/search URL for cookie-protected customer communication. https://docs.truvity.com/api/api-keys/search ##### Request samples * Payload * Go * Java * TypeScript Content type application/json Copy Expand all Collapse all `{ "filter": [ { "annotations": [ { "operator": "EQUAL", "key": "string", "value": "string" } ], "created_at": { "operator": "BETWEEN", "left": "2019-08-24T14:15:22Z", "right": "2019-08-24T14:15:22Z" }, "data": { "expiration": { "operator": "BETWEEN", "left": "2019-08-24T14:15:22Z", "right": "2019-08-24T14:15:22Z" }, "subject_id": { "operator": "EQUAL", "value": "a860a344-d7b2-406e-828e-8d442f23f344" } }, "deleted_at": { "operator": "BETWEEN", "left": "2019-08-24T14:15:22Z", "right": "2019-08-24T14:15:22Z" }, "etag": { "operator": "EQUAL", "value": "string" }, "id": { "operator": "EQUAL", "value": "a860a344-d7b2-406e-828e-8d442f23f344" }, "labels": [ { "operator": "EQUAL", "key": "string", "value": "string" } ], "modified_at": { "operator": "BETWEEN", "left": "2019-08-24T14:15:22Z", "right": "2019-08-24T14:15:22Z" }, "revision": { "operator": "EQUAL", "value": 1 } } ], "sort": [ { "field": "DATA_EXPIRATION", "order": "ASC" } ] }` ##### Response samples * 200 * 400 * 401 * 403 * 415 * 429 * 500 * default Content type application/json Copy Expand all Collapse all `{ "items": [ { "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "expiration": "2019-08-24T14:15:22Z", "subject_id": "80e197be-61ad-4068-b4ff-a483fb5c18f9" }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 } ] }` #### [](#tag/api-keys/operation/ApiKeyDelete)Delete API Key. Delete API Key's resource. ###### Authorizations: *ApiKey* ###### path Parameters | | | | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | idrequired | string<uuid>The primary and unique identifier of the resource (inside tenant) according to [RFC 4122](https://www.rfc-editor.org/info/rfc4122). | ###### header Parameters | | | | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Idempotency-Key | string\[ 32 .. 256 ] characters\[a-zA-Z0-9-]{32,256}From [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **Idempotency-Key** is a free identifier created by the client to identify a request. It is used by the service to identify repeated request to ensure idempotent behavior by sending the same (or a similar) response without executing the request a second time.Clients should be careful as any subsequent requests with the same key may return the same response without further check. Thus, it is recommended to use a UUID version 4 (random) or any other random string with enough entropy to avoid collisions.Keys expire after 24 hours. Clients are responsible to stay within this limit, if they require idempotent behavior.See [API Guideline Rule #181](https://opensource.zalando.com/restful-api-guidelines/#230) for further details. | | If-Matchrequired | stringFrom [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **If-Match** header field is used to declare a list of identifiers that are required to match the current resource version identifier in at least one position as a pre-condition for executing the request on the server side. This behavior is used to validate and reject optimistic updates, by checking if the resource version a consumer has based his changes on is outdated on arrival of the change request to prevent lost updates.If the pre-condition fails the server will respond with status code **412** (Precondition Failed). See [RFC 9110 Section 13.1.1](https://tools.ietf.org/html/rfc9110#section-13.1.1) as well as \[API Guideline Rule #182]\[api-182] for further details.\[api-182]: . | ##### Responses **204** HTTP 204 - No content. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **404** The schema represents an HTTP "Not Found" status code. **405** The schema represents an HTTP "Method Not Allowed" status code. **412** The schema represents an HTTP "Precondition Failed" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. delete/api-keys/{id} URL for header-protected customer communication. https://api.truvity.{zone}/api-keys/{id} URL for cookie-protected customer communication. https://docs.truvity.com/api/api-keys/{id} ##### Request samples * Go * Java * TypeScript Copy ##### Response samples * 400 * 401 * 403 * 404 * 405 * 412 * 429 * 500 * default Content type application/problem+json Example /bad-request/bad-request Copy Expand all Collapse all `{ "detail": "string", "errors": [ { "location": "string", "message": "string", "value": null } ], "instance": "http://example.com", "status": 100, "title": "string", "type": "/bad-request" }` #### [](#tag/api-keys/operation/ApiKeyLatest)Get the latest version of API Key. Get the latest version of API Key. ###### Authorizations: *ApiKey* ###### path Parameters | | | | ---------- | ------------------------------------------------------------------- | | idrequired | string<uuid>The ID of the resource. | ###### header Parameters | | | | ------------- | ----------------------------------------------------- | | If-None-Match | stringThe ETag of the latest version of the resource. | ##### Responses **200** Response with the latest API Key. **304** HTTP 304 - Not modified. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **404** The schema represents an HTTP "Not Found" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. get/api-keys/{id} URL for header-protected customer communication. https://api.truvity.{zone}/api-keys/{id} URL for cookie-protected customer communication. https://docs.truvity.com/api/api-keys/{id} ##### Request samples * Go * Java * TypeScript Copy ##### Response samples * 200 * 400 * 401 * 403 * 404 * 429 * 500 * default Content type application/vnd.truvity.api-key+json;version=1 Copy Expand all Collapse all `{ "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "expiration": "2019-08-24T14:15:22Z", "subject_id": "80e197be-61ad-4068-b4ff-a483fb5c18f9" }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 }` #### [](#tag/api-keys/operation/ApiKeyUpdateAnnotations)Update annotations. Update annotations of API Key's resource. ###### Authorizations: *ApiKey* ###### path Parameters | | | | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | idrequired | string<uuid>The primary and unique identifier of the resource (inside tenant) according to [RFC 4122](https://www.rfc-editor.org/info/rfc4122). | ###### header Parameters | | | | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Idempotency-Key | string\[ 32 .. 256 ] characters\[a-zA-Z0-9-]{32,256}From [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **Idempotency-Key** is a free identifier created by the client to identify a request. It is used by the service to identify repeated request to ensure idempotent behavior by sending the same (or a similar) response without executing the request a second time.Clients should be careful as any subsequent requests with the same key may return the same response without further check. Thus, it is recommended to use a UUID version 4 (random) or any other random string with enough entropy to avoid collisions.Keys expire after 24 hours. Clients are responsible to stay within this limit, if they require idempotent behavior.See [API Guideline Rule #181](https://opensource.zalando.com/restful-api-guidelines/#230) for further details. | | If-Matchrequired | stringFrom [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **If-Match** header field is used to declare a list of identifiers that are required to match the current resource version identifier in at least one position as a pre-condition for executing the request on the server side. This behavior is used to validate and reject optimistic updates, by checking if the resource version a consumer has based his changes on is outdated on arrival of the change request to prevent lost updates.If the pre-condition fails the server will respond with status code **412** (Precondition Failed). See [RFC 9110 Section 13.1.1](https://tools.ietf.org/html/rfc9110#section-13.1.1) as well as \[API Guideline Rule #182]\[api-182] for further details.\[api-182]: . | ###### Request Body schema: application/jsonrequired | | | | ----------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------- | | annotationsrequired | objectThe annotations of the resource. | | property name\* additional property string <= 128 characters ^\[^\n]{0,128}$ Value of the resource annotation. | | ##### Responses **200** Response with the updated API Key. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **404** The schema represents an HTTP "Not Found" status code. **405** The schema represents an HTTP "Method Not Allowed" status code. **412** The schema represents an HTTP "Precondition Failed" status code. **415** The schema represents an HTTP "Unsupported Media Type" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. patch/api-keys/{id}/annotations URL for header-protected customer communication. https://api.truvity.{zone}/api-keys/{id}/annotations URL for cookie-protected customer communication. https://docs.truvity.com/api/api-keys/{id}/annotations ##### Request samples * Payload * Go * Java * TypeScript Content type application/json Copy Expand all Collapse all `{ "annotations": { "property1": "string", "property2": "string" } }` ##### Response samples * 200 * 400 * 401 * 403 * 404 * 405 * 412 * 415 * 429 * 500 * default Content type application/vnd.truvity.api-key+json;version=1 Copy Expand all Collapse all `{ "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "expiration": "2019-08-24T14:15:22Z", "subject_id": "80e197be-61ad-4068-b4ff-a483fb5c18f9" }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 }` #### [](#tag/api-keys/operation/ApiKeyUpdateLabels)Update labels. Update labels of API Key's resource. ###### Authorizations: *ApiKey* ###### path Parameters | | | | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | idrequired | string<uuid>The primary and unique identifier of the resource (inside tenant) according to [RFC 4122](https://www.rfc-editor.org/info/rfc4122). | ###### header Parameters | | | | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Idempotency-Key | string\[ 32 .. 256 ] characters\[a-zA-Z0-9-]{32,256}From [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **Idempotency-Key** is a free identifier created by the client to identify a request. It is used by the service to identify repeated request to ensure idempotent behavior by sending the same (or a similar) response without executing the request a second time.Clients should be careful as any subsequent requests with the same key may return the same response without further check. Thus, it is recommended to use a UUID version 4 (random) or any other random string with enough entropy to avoid collisions.Keys expire after 24 hours. Clients are responsible to stay within this limit, if they require idempotent behavior.See [API Guideline Rule #181](https://opensource.zalando.com/restful-api-guidelines/#230) for further details. | | If-Matchrequired | stringFrom [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **If-Match** header field is used to declare a list of identifiers that are required to match the current resource version identifier in at least one position as a pre-condition for executing the request on the server side. This behavior is used to validate and reject optimistic updates, by checking if the resource version a consumer has based his changes on is outdated on arrival of the change request to prevent lost updates.If the pre-condition fails the server will respond with status code **412** (Precondition Failed). See [RFC 9110 Section 13.1.1](https://tools.ietf.org/html/rfc9110#section-13.1.1) as well as \[API Guideline Rule #182]\[api-182] for further details.\[api-182]: . | ###### Request Body schema: application/jsonrequired | | | | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------- | | labelsrequired | objectThe labels of the resource. | | property name\* additional property string <= 63 characters ^(?:\[a-zA-Z0-9]\(?:\[a-zA-Z0-9\\.\\-\_]{0,61}\[a-zA...Show pattern Value of the resource label. | | ##### Responses **200** Response with the updated API Key. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **404** The schema represents an HTTP "Not Found" status code. **405** The schema represents an HTTP "Method Not Allowed" status code. **412** The schema represents an HTTP "Precondition Failed" status code. **415** The schema represents an HTTP "Unsupported Media Type" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. patch/api-keys/{id}/labels URL for header-protected customer communication. https://api.truvity.{zone}/api-keys/{id}/labels URL for cookie-protected customer communication. https://docs.truvity.com/api/api-keys/{id}/labels ##### Request samples * Payload * Go * Java * TypeScript Content type application/json Copy Expand all Collapse all `{ "labels": { "property1": "string", "property2": "string" } }` ##### Response samples * 200 * 400 * 401 * 403 * 404 * 405 * 412 * 415 * 429 * 500 * default Content type application/vnd.truvity.api-key+json;version=1 Copy Expand all Collapse all `{ "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "expiration": "2019-08-24T14:15:22Z", "subject_id": "80e197be-61ad-4068-b4ff-a483fb5c18f9" }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 }` #### [](#tag/api-keys/operation/ApiKeyRestore)Restore API Key. Restore API Key's resource. ###### Authorizations: *ApiKey* ###### path Parameters | | | | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | idrequired | string<uuid>The primary and unique identifier of the resource (inside tenant) according to [RFC 4122](https://www.rfc-editor.org/info/rfc4122). | ###### header Parameters | | | | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Idempotency-Key | string\[ 32 .. 256 ] characters\[a-zA-Z0-9-]{32,256}From [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **Idempotency-Key** is a free identifier created by the client to identify a request. It is used by the service to identify repeated request to ensure idempotent behavior by sending the same (or a similar) response without executing the request a second time.Clients should be careful as any subsequent requests with the same key may return the same response without further check. Thus, it is recommended to use a UUID version 4 (random) or any other random string with enough entropy to avoid collisions.Keys expire after 24 hours. Clients are responsible to stay within this limit, if they require idempotent behavior.See [API Guideline Rule #181](https://opensource.zalando.com/restful-api-guidelines/#230) for further details. | | If-Matchrequired | stringFrom [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **If-Match** header field is used to declare a list of identifiers that are required to match the current resource version identifier in at least one position as a pre-condition for executing the request on the server side. This behavior is used to validate and reject optimistic updates, by checking if the resource version a consumer has based his changes on is outdated on arrival of the change request to prevent lost updates.If the pre-condition fails the server will respond with status code **412** (Precondition Failed). See [RFC 9110 Section 13.1.1](https://tools.ietf.org/html/rfc9110#section-13.1.1) as well as \[API Guideline Rule #182]\[api-182] for further details.\[api-182]: . | ##### Responses **200** Response with the restored API Key. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **404** The schema represents an HTTP "Not Found" status code. **405** The schema represents an HTTP "Method Not Allowed" status code. **412** The schema represents an HTTP "Precondition Failed" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. post/api-keys/{id}/restore URL for header-protected customer communication. https://api.truvity.{zone}/api-keys/{id}/restore URL for cookie-protected customer communication. https://docs.truvity.com/api/api-keys/{id}/restore ##### Request samples * Go * Java * TypeScript Copy ##### Response samples * 200 * 400 * 401 * 403 * 404 * 405 * 412 * 429 * 500 * default Content type application/vnd.truvity.api-key+json;version=1 Copy Expand all Collapse all `{ "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "expiration": "2019-08-24T14:15:22Z", "subject_id": "80e197be-61ad-4068-b4ff-a483fb5c18f9" }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 }` #### [](#tag/api-keys/operation/ApiKeyHistory)Read API Key's history. History of the API Key's resources. ###### Authorizations: *ApiKey* ###### path Parameters | | | | ---------- | ------------------------------------------------------------------- | | idrequired | string<uuid>The ID of the resource. | ###### header Parameters | | | | ------------- | ----------------------------------------------------- | | If-None-Match | stringThe ETag of the latest version of the resource. | ##### Responses **200** Response with the history of API Key. **304** HTTP 304 - Not modified. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **404** The schema represents an HTTP "Not Found" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. get/api-keys/{id}/revisions URL for header-protected customer communication. https://api.truvity.{zone}/api-keys/{id}/revisions URL for cookie-protected customer communication. https://docs.truvity.com/api/api-keys/{id}/revisions ##### Request samples * Go * Java * TypeScript Copy ##### Response samples * 200 * 400 * 401 * 403 * 404 * 429 * 500 * default Content type application/json Copy Expand all Collapse all `{ "items": [ { "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "expiration": "2019-08-24T14:15:22Z", "subject_id": "80e197be-61ad-4068-b4ff-a483fb5c18f9" }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 } ] }` #### [](#tag/api-keys/operation/ApiKeyRevision)Read the specific version of the API Key. Read the specific version of the API Key's resource. ###### Authorizations: *ApiKey* ###### path Parameters | | | | ---------------- | ----------------------------------------------------------------------------------------------------------- | | idrequired | string<uuid>The ID of the resource. | | revisionrequired | integer<int32>\[ 1 .. 999999 ]The revision of the resource. | ###### header Parameters | | | | ------------- | ----------------------------------------------------- | | If-None-Match | stringThe ETag of the latest version of the resource. | ##### Responses **200** The requested revision of the API Key. **304** HTTP 304 - Not modified. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **404** The schema represents an HTTP "Not Found" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. get/api-keys/{id}/revisions/{revision} URL for header-protected customer communication. https://api.truvity.{zone}/api-keys/{id}/revisions/{revision} URL for cookie-protected customer communication. https://docs.truvity.com/api/api-keys/{id}/revisions/{revision} ##### Request samples * Go * Java * TypeScript Copy ##### Response samples * 200 * 400 * 401 * 403 * 404 * 429 * 500 * default Content type application/json Copy Expand all Collapse all `{ "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "expiration": "2019-08-24T14:15:22Z", "subject_id": "80e197be-61ad-4068-b4ff-a483fb5c18f9" }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 }` #### [](#tag/credentials)Credential The API to manage Verifiable Credentials. #### [](#tag/credentials/operation/CredentialImport)Import Credential. Import a Verifiable Credential's resource with a **blob\_id**. To get **blob\_id** call [Upload](#tag/credentials/operation/CredentialUpload) first. ###### Authorizations: *ApiKey* ###### query Parameters | | | | ---------------- | ---------------------------------------------------------------------------------------------------------------- | | blob\_idrequired | string<uuid>The ID that returned on Upload operation in blob\_id field. | | draft\_id | string<uuid>The ID of a Draft that was exported to get the importing Credential. | ###### header Parameters | | | | --------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Idempotency-Key | string\[ 32 .. 256 ] characters\[a-zA-Z0-9-]{32,256}From [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **Idempotency-Key** is a free identifier created by the client to identify a request. It is used by the service to identify repeated request to ensure idempotent behavior by sending the same (or a similar) response without executing the request a second time.Clients should be careful as any subsequent requests with the same key may return the same response without further check. Thus, it is recommended to use a UUID version 4 (random) or any other random string with enough entropy to avoid collisions.Keys expire after 24 hours. Clients are responsible to stay within this limit, if they require idempotent behavior.See [API Guideline Rule #181](https://opensource.zalando.com/restful-api-guidelines/#230) for further details. | ###### Request Body schema: application/jsonrequired | | | | ----------- | -------------------------------------- | | annotations | objectThe annotations of the resource. | | labels | objectThe labels of the resource. | ##### Responses **201** The imported Credential. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **404** The schema represents an HTTP "Not Found" status code. **415** The schema represents an HTTP "Unsupported Media Type" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. post/credentials/import URL for header-protected customer communication. https://api.truvity.{zone}/credentials/import URL for cookie-protected customer communication. https://docs.truvity.com/api/credentials/import ##### Request samples * Payload * Go * Java * TypeScript Content type application/json Copy Expand all Collapse all `{ "annotations": { "property1": "string", "property2": "string" }, "labels": { "property1": "string", "property2": "string" } }` ##### Response samples * 201 * 400 * 401 * 403 * 404 * 415 * 429 * 500 * default Content type application/vnd.truvity.credential+json;version=1 Copy Expand all Collapse all `{ "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "data_model": { "flavor_name": "VC1_1", "expirationDate": "2019-08-24T14:15:22Z", "holder": "http://example.com", "id": "http://example.com", "issuanceDate": "2019-08-24T14:15:22Z", "issuer": "http://example.com", "proof": { "id": "string", "type": "string" }, "type": [ "string" ] }, "digest_multibase": "string", "holder": "http://example.com", "id": "http://example.com", "issuer": "http://example.com", "linked_credential_refs": [ { "blob_id": "http://example.com", "digest_multibase": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f" } ], "linked_file_refs": [ { "blob_id": "http://example.com", "digest_multibase": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f" } ], "type": [ "string" ], "valid_from": "2019-08-24T14:15:22Z", "valid_until": "2019-08-24T14:15:22Z" }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 }` #### [](#tag/credentials/operation/CredentialSearch)Search for Credentials. Search for Credentials with extended filters capabilities. ###### Authorizations: *ApiKey* ###### Request Body schema: application/jsonrequired | | | | ------ | ----------------------------------------------------------------------------------------------------------------- | | filter | Array of objects (CredentialFilter)<= 4 itemsThe filter to apply to the search. | | sort | Array of objects (CredentialSort)<= 4 itemsThe sort order to apply to the search. | ##### Responses **200** The search results of Credential. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **415** The schema represents an HTTP "Unsupported Media Type" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. post/credentials/search URL for header-protected customer communication. https://api.truvity.{zone}/credentials/search URL for cookie-protected customer communication. https://docs.truvity.com/api/credentials/search ##### Request samples * Payload * Go * Java * TypeScript Content type application/json Copy Expand all Collapse all `{ "filter": [ { "annotations": [ { "operator": "EQUAL", "key": "string", "value": "string" } ], "created_at": { "operator": "BETWEEN", "left": "2019-08-24T14:15:22Z", "right": "2019-08-24T14:15:22Z" }, "data": { "digest_multibase": { "operator": "EQUAL", "value": "string" }, "holder": { "operator": "EQUAL", "value": "http://example.com" }, "id": { "operator": "EQUAL", "value": "http://example.com" }, "issuer": { "operator": "EQUAL", "value": "http://example.com" }, "type": { "operator": "IN", "values": [ "string" ] }, "valid_from": { "operator": "BETWEEN", "left": "2019-08-24T14:15:22Z", "right": "2019-08-24T14:15:22Z" }, "valid_until": { "operator": "BETWEEN", "left": "2019-08-24T14:15:22Z", "right": "2019-08-24T14:15:22Z" } }, "deleted_at": { "operator": "BETWEEN", "left": "2019-08-24T14:15:22Z", "right": "2019-08-24T14:15:22Z" }, "etag": { "operator": "EQUAL", "value": "string" }, "id": { "operator": "EQUAL", "value": "a860a344-d7b2-406e-828e-8d442f23f344" }, "labels": [ { "operator": "EQUAL", "key": "string", "value": "string" } ], "modified_at": { "operator": "BETWEEN", "left": "2019-08-24T14:15:22Z", "right": "2019-08-24T14:15:22Z" }, "revision": { "operator": "EQUAL", "value": 1 }, "linked_credentials": { "annotations": [ { "operator": "EQUAL", "key": "string", "value": "string" } ], "created_at": { "operator": "BETWEEN", "left": "2019-08-24T14:15:22Z", "right": "2019-08-24T14:15:22Z" }, "data": { "digest_multibase": { "operator": "EQUAL", "value": "string" }, "holder": { "operator": "EQUAL", "value": "http://example.com" }, "id": { "operator": "EQUAL", "value": "http://example.com" }, "issuer": { "operator": "EQUAL", "value": "http://example.com" }, "type": { "operator": "IN", "values": [ "string" ] }, "valid_from": { "operator": "BETWEEN", "left": "2019-08-24T14:15:22Z", "right": "2019-08-24T14:15:22Z" }, "valid_until": { "operator": "BETWEEN", "left": "2019-08-24T14:15:22Z", "right": "2019-08-24T14:15:22Z" } }, "deleted_at": { "operator": "BETWEEN", "left": "2019-08-24T14:15:22Z", "right": "2019-08-24T14:15:22Z" }, "etag": { "operator": "EQUAL", "value": "string" }, "id": { "operator": "EQUAL", "value": "a860a344-d7b2-406e-828e-8d442f23f344" }, "labels": [ { "operator": "EQUAL", "key": "string", "value": "string" } ], "modified_at": { "operator": "BETWEEN", "left": "2019-08-24T14:15:22Z", "right": "2019-08-24T14:15:22Z" }, "revision": { "operator": "EQUAL", "value": 1 } }, "linked_files": { "annotations": [ { "operator": "EQUAL", "key": "string", "value": "string" } ], "created_at": { "operator": "BETWEEN", "left": "2019-08-24T14:15:22Z", "right": "2019-08-24T14:15:22Z" }, "data": { "content_type": { "operator": "EQUAL", "value": "string" }, "digest_multibase": { "operator": "EQUAL", "value": "string" }, "filename": { "operator": "EQUAL", "value": "string" }, "filesize": { "operator": "EQUAL", "value": 1 }, "id": { "operator": "EQUAL", "value": "http://example.com" } }, "deleted_at": { "operator": "BETWEEN", "left": "2019-08-24T14:15:22Z", "right": "2019-08-24T14:15:22Z" }, "etag": { "operator": "EQUAL", "value": "string" }, "id": { "operator": "EQUAL", "value": "a860a344-d7b2-406e-828e-8d442f23f344" }, "labels": [ { "operator": "EQUAL", "key": "string", "value": "string" } ], "modified_at": { "operator": "BETWEEN", "left": "2019-08-24T14:15:22Z", "right": "2019-08-24T14:15:22Z" }, "revision": { "operator": "EQUAL", "value": 1 } } } ], "sort": [ { "field": "DATA_ID", "order": "ASC" } ] }` ##### Response samples * 200 * 400 * 401 * 403 * 415 * 429 * 500 * default Content type application/json Copy Expand all Collapse all `{ "items": [ { "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "data_model": { "flavor_name": "VC1_1", "expirationDate": "2019-08-24T14:15:22Z", "holder": "http://example.com", "id": "http://example.com", "issuanceDate": "2019-08-24T14:15:22Z", "issuer": "http://example.com", "proof": { "id": "string", "type": "string" }, "type": [ "string" ] }, "digest_multibase": "string", "holder": "http://example.com", "id": "http://example.com", "issuer": "http://example.com", "linked_credential_refs": [ { "blob_id": "http://example.com", "digest_multibase": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f" } ], "linked_file_refs": [ { "blob_id": "http://example.com", "digest_multibase": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f" } ], "type": [ "string" ], "valid_from": "2019-08-24T14:15:22Z", "valid_until": "2019-08-24T14:15:22Z" }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 } ] }` #### [](#tag/credentials/operation/CredentialUpload)Upload Credential's blob. Initiates a Credential blob upload, returning a pre-signed S3 URL. Response contains: * **blob\_id** (required for Credential creation) * **upload\_uri** (pre-signed URL for upload) * **timeout** (expiration in seconds). ###### Authorizations: *ApiKey* ###### header Parameters | | | | --------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Idempotency-Key | string\[ 32 .. 256 ] characters\[a-zA-Z0-9-]{32,256}From [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **Idempotency-Key** is a free identifier created by the client to identify a request. It is used by the service to identify repeated request to ensure idempotent behavior by sending the same (or a similar) response without executing the request a second time.Clients should be careful as any subsequent requests with the same key may return the same response without further check. Thus, it is recommended to use a UUID version 4 (random) or any other random string with enough entropy to avoid collisions.Keys expire after 24 hours. Clients are responsible to stay within this limit, if they require idempotent behavior.See [API Guideline Rule #181](https://opensource.zalando.com/restful-api-guidelines/#230) for further details. | ##### Responses **200** The result of uploading of Credential's resource. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. post/credentials/upload URL for header-protected customer communication. https://api.truvity.{zone}/credentials/upload URL for cookie-protected customer communication. https://docs.truvity.com/api/credentials/upload ##### Request samples * Go * Java * TypeScript Copy ##### Response samples * 200 * 400 * 401 * 403 * 429 * 500 * default Content type application/json Copy `{ "blob_id": "8249af2f-dd23-416e-b9c4-6cb13a792190", "timeout": 1, "upload_uri": "http://example.com" }` #### [](#tag/credentials/operation/CredentialDelete)Delete Credential. Delete Credential's resource. ###### Authorizations: *ApiKey* ###### path Parameters | | | | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | idrequired | string<uuid>The primary and unique identifier of the resource (inside tenant) according to [RFC 4122](https://www.rfc-editor.org/info/rfc4122). | ###### header Parameters | | | | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Idempotency-Key | string\[ 32 .. 256 ] characters\[a-zA-Z0-9-]{32,256}From [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **Idempotency-Key** is a free identifier created by the client to identify a request. It is used by the service to identify repeated request to ensure idempotent behavior by sending the same (or a similar) response without executing the request a second time.Clients should be careful as any subsequent requests with the same key may return the same response without further check. Thus, it is recommended to use a UUID version 4 (random) or any other random string with enough entropy to avoid collisions.Keys expire after 24 hours. Clients are responsible to stay within this limit, if they require idempotent behavior.See [API Guideline Rule #181](https://opensource.zalando.com/restful-api-guidelines/#230) for further details. | | If-Matchrequired | stringFrom [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **If-Match** header field is used to declare a list of identifiers that are required to match the current resource version identifier in at least one position as a pre-condition for executing the request on the server side. This behavior is used to validate and reject optimistic updates, by checking if the resource version a consumer has based his changes on is outdated on arrival of the change request to prevent lost updates.If the pre-condition fails the server will respond with status code **412** (Precondition Failed). See [RFC 9110 Section 13.1.1](https://tools.ietf.org/html/rfc9110#section-13.1.1) as well as \[API Guideline Rule #182]\[api-182] for further details.\[api-182]: . | ##### Responses **204** HTTP 204 - No content. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **404** The schema represents an HTTP "Not Found" status code. **405** The schema represents an HTTP "Method Not Allowed" status code. **412** The schema represents an HTTP "Precondition Failed" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. delete/credentials/{id} URL for header-protected customer communication. https://api.truvity.{zone}/credentials/{id} URL for cookie-protected customer communication. https://docs.truvity.com/api/credentials/{id} ##### Request samples * Go * Java * TypeScript Copy ##### Response samples * 400 * 401 * 403 * 404 * 405 * 412 * 429 * 500 * default Content type application/problem+json Example /bad-request/bad-request Copy Expand all Collapse all `{ "detail": "string", "errors": [ { "location": "string", "message": "string", "value": null } ], "instance": "http://example.com", "status": 100, "title": "string", "type": "/bad-request" }` #### [](#tag/credentials/operation/CredentialLatest)Get the latest version of Credential. Get the latest version of Credential. ###### Authorizations: *ApiKey* ###### path Parameters | | | | ---------- | ------------------------------------------------------------------- | | idrequired | string<uuid>The ID of the resource. | ###### header Parameters | | | | ------------- | ----------------------------------------------------- | | If-None-Match | stringThe ETag of the latest version of the resource. | ##### Responses **200** Response with the latest Credential. **304** HTTP 304 - Not modified. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **404** The schema represents an HTTP "Not Found" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. get/credentials/{id} URL for header-protected customer communication. https://api.truvity.{zone}/credentials/{id} URL for cookie-protected customer communication. https://docs.truvity.com/api/credentials/{id} ##### Request samples * Go * Java * TypeScript Copy ##### Response samples * 200 * 400 * 401 * 403 * 404 * 429 * 500 * default Content type application/vnd.truvity.credential+json;version=1 Copy Expand all Collapse all `{ "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "data_model": { "flavor_name": "VC1_1", "expirationDate": "2019-08-24T14:15:22Z", "holder": "http://example.com", "id": "http://example.com", "issuanceDate": "2019-08-24T14:15:22Z", "issuer": "http://example.com", "proof": { "id": "string", "type": "string" }, "type": [ "string" ] }, "digest_multibase": "string", "holder": "http://example.com", "id": "http://example.com", "issuer": "http://example.com", "linked_credential_refs": [ { "blob_id": "http://example.com", "digest_multibase": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f" } ], "linked_file_refs": [ { "blob_id": "http://example.com", "digest_multibase": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f" } ], "type": [ "string" ], "valid_from": "2019-08-24T14:15:22Z", "valid_until": "2019-08-24T14:15:22Z" }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 }` #### [](#tag/credentials/operation/CredentialUpdateAnnotations)Update annotations. Update annotations of Credential's resource. ###### Authorizations: *ApiKey* ###### path Parameters | | | | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | idrequired | string<uuid>The primary and unique identifier of the resource (inside tenant) according to [RFC 4122](https://www.rfc-editor.org/info/rfc4122). | ###### header Parameters | | | | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Idempotency-Key | string\[ 32 .. 256 ] characters\[a-zA-Z0-9-]{32,256}From [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **Idempotency-Key** is a free identifier created by the client to identify a request. It is used by the service to identify repeated request to ensure idempotent behavior by sending the same (or a similar) response without executing the request a second time.Clients should be careful as any subsequent requests with the same key may return the same response without further check. Thus, it is recommended to use a UUID version 4 (random) or any other random string with enough entropy to avoid collisions.Keys expire after 24 hours. Clients are responsible to stay within this limit, if they require idempotent behavior.See [API Guideline Rule #181](https://opensource.zalando.com/restful-api-guidelines/#230) for further details. | | If-Matchrequired | stringFrom [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **If-Match** header field is used to declare a list of identifiers that are required to match the current resource version identifier in at least one position as a pre-condition for executing the request on the server side. This behavior is used to validate and reject optimistic updates, by checking if the resource version a consumer has based his changes on is outdated on arrival of the change request to prevent lost updates.If the pre-condition fails the server will respond with status code **412** (Precondition Failed). See [RFC 9110 Section 13.1.1](https://tools.ietf.org/html/rfc9110#section-13.1.1) as well as \[API Guideline Rule #182]\[api-182] for further details.\[api-182]: . | ###### Request Body schema: application/jsonrequired | | | | ----------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------- | | annotationsrequired | objectThe annotations of the resource. | | property name\* additional property string <= 128 characters ^\[^\n]{0,128}$ Value of the resource annotation. | | ##### Responses **200** Response with the updated Credential. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **404** The schema represents an HTTP "Not Found" status code. **405** The schema represents an HTTP "Method Not Allowed" status code. **412** The schema represents an HTTP "Precondition Failed" status code. **415** The schema represents an HTTP "Unsupported Media Type" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. patch/credentials/{id}/annotations URL for header-protected customer communication. https://api.truvity.{zone}/credentials/{id}/annotations URL for cookie-protected customer communication. https://docs.truvity.com/api/credentials/{id}/annotations ##### Request samples * Payload * Go * Java * TypeScript Content type application/json Copy Expand all Collapse all `{ "annotations": { "property1": "string", "property2": "string" } }` ##### Response samples * 200 * 400 * 401 * 403 * 404 * 405 * 412 * 415 * 429 * 500 * default Content type application/vnd.truvity.credential+json;version=1 Copy Expand all Collapse all `{ "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "data_model": { "flavor_name": "VC1_1", "expirationDate": "2019-08-24T14:15:22Z", "holder": "http://example.com", "id": "http://example.com", "issuanceDate": "2019-08-24T14:15:22Z", "issuer": "http://example.com", "proof": { "id": "string", "type": "string" }, "type": [ "string" ] }, "digest_multibase": "string", "holder": "http://example.com", "id": "http://example.com", "issuer": "http://example.com", "linked_credential_refs": [ { "blob_id": "http://example.com", "digest_multibase": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f" } ], "linked_file_refs": [ { "blob_id": "http://example.com", "digest_multibase": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f" } ], "type": [ "string" ], "valid_from": "2019-08-24T14:15:22Z", "valid_until": "2019-08-24T14:15:22Z" }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 }` #### [](#tag/credentials/operation/CredentialUpdateLabels)Update labels. Update labels of Credential's resource. ###### Authorizations: *ApiKey* ###### path Parameters | | | | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | idrequired | string<uuid>The primary and unique identifier of the resource (inside tenant) according to [RFC 4122](https://www.rfc-editor.org/info/rfc4122). | ###### header Parameters | | | | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Idempotency-Key | string\[ 32 .. 256 ] characters\[a-zA-Z0-9-]{32,256}From [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **Idempotency-Key** is a free identifier created by the client to identify a request. It is used by the service to identify repeated request to ensure idempotent behavior by sending the same (or a similar) response without executing the request a second time.Clients should be careful as any subsequent requests with the same key may return the same response without further check. Thus, it is recommended to use a UUID version 4 (random) or any other random string with enough entropy to avoid collisions.Keys expire after 24 hours. Clients are responsible to stay within this limit, if they require idempotent behavior.See [API Guideline Rule #181](https://opensource.zalando.com/restful-api-guidelines/#230) for further details. | | If-Matchrequired | stringFrom [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **If-Match** header field is used to declare a list of identifiers that are required to match the current resource version identifier in at least one position as a pre-condition for executing the request on the server side. This behavior is used to validate and reject optimistic updates, by checking if the resource version a consumer has based his changes on is outdated on arrival of the change request to prevent lost updates.If the pre-condition fails the server will respond with status code **412** (Precondition Failed). See [RFC 9110 Section 13.1.1](https://tools.ietf.org/html/rfc9110#section-13.1.1) as well as \[API Guideline Rule #182]\[api-182] for further details.\[api-182]: . | ###### Request Body schema: application/jsonrequired | | | | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------- | | labelsrequired | objectThe labels of the resource. | | property name\* additional property string <= 63 characters ^(?:\[a-zA-Z0-9]\(?:\[a-zA-Z0-9\\.\\-\_]{0,61}\[a-zA...Show pattern Value of the resource label. | | ##### Responses **200** Response with the updated Credential. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **404** The schema represents an HTTP "Not Found" status code. **405** The schema represents an HTTP "Method Not Allowed" status code. **412** The schema represents an HTTP "Precondition Failed" status code. **415** The schema represents an HTTP "Unsupported Media Type" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. patch/credentials/{id}/labels URL for header-protected customer communication. https://api.truvity.{zone}/credentials/{id}/labels URL for cookie-protected customer communication. https://docs.truvity.com/api/credentials/{id}/labels ##### Request samples * Payload * Go * Java * TypeScript Content type application/json Copy Expand all Collapse all `{ "labels": { "property1": "string", "property2": "string" } }` ##### Response samples * 200 * 400 * 401 * 403 * 404 * 405 * 412 * 415 * 429 * 500 * default Content type application/vnd.truvity.credential+json;version=1 Copy Expand all Collapse all `{ "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "data_model": { "flavor_name": "VC1_1", "expirationDate": "2019-08-24T14:15:22Z", "holder": "http://example.com", "id": "http://example.com", "issuanceDate": "2019-08-24T14:15:22Z", "issuer": "http://example.com", "proof": { "id": "string", "type": "string" }, "type": [ "string" ] }, "digest_multibase": "string", "holder": "http://example.com", "id": "http://example.com", "issuer": "http://example.com", "linked_credential_refs": [ { "blob_id": "http://example.com", "digest_multibase": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f" } ], "linked_file_refs": [ { "blob_id": "http://example.com", "digest_multibase": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f" } ], "type": [ "string" ], "valid_from": "2019-08-24T14:15:22Z", "valid_until": "2019-08-24T14:15:22Z" }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 }` #### [](#tag/credentials/operation/CredentialRestore)Restore Credential. Restore Credential's resource. ###### Authorizations: *ApiKey* ###### path Parameters | | | | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | idrequired | string<uuid>The primary and unique identifier of the resource (inside tenant) according to [RFC 4122](https://www.rfc-editor.org/info/rfc4122). | ###### header Parameters | | | | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Idempotency-Key | string\[ 32 .. 256 ] characters\[a-zA-Z0-9-]{32,256}From [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **Idempotency-Key** is a free identifier created by the client to identify a request. It is used by the service to identify repeated request to ensure idempotent behavior by sending the same (or a similar) response without executing the request a second time.Clients should be careful as any subsequent requests with the same key may return the same response without further check. Thus, it is recommended to use a UUID version 4 (random) or any other random string with enough entropy to avoid collisions.Keys expire after 24 hours. Clients are responsible to stay within this limit, if they require idempotent behavior.See [API Guideline Rule #181](https://opensource.zalando.com/restful-api-guidelines/#230) for further details. | | If-Matchrequired | stringFrom [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **If-Match** header field is used to declare a list of identifiers that are required to match the current resource version identifier in at least one position as a pre-condition for executing the request on the server side. This behavior is used to validate and reject optimistic updates, by checking if the resource version a consumer has based his changes on is outdated on arrival of the change request to prevent lost updates.If the pre-condition fails the server will respond with status code **412** (Precondition Failed). See [RFC 9110 Section 13.1.1](https://tools.ietf.org/html/rfc9110#section-13.1.1) as well as \[API Guideline Rule #182]\[api-182] for further details.\[api-182]: . | ##### Responses **200** Response with the restored Credential. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **404** The schema represents an HTTP "Not Found" status code. **405** The schema represents an HTTP "Method Not Allowed" status code. **412** The schema represents an HTTP "Precondition Failed" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. post/credentials/{id}/restore URL for header-protected customer communication. https://api.truvity.{zone}/credentials/{id}/restore URL for cookie-protected customer communication. https://docs.truvity.com/api/credentials/{id}/restore ##### Request samples * Go * Java * TypeScript Copy ##### Response samples * 200 * 400 * 401 * 403 * 404 * 405 * 412 * 429 * 500 * default Content type application/vnd.truvity.credential+json;version=1 Copy Expand all Collapse all `{ "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "data_model": { "flavor_name": "VC1_1", "expirationDate": "2019-08-24T14:15:22Z", "holder": "http://example.com", "id": "http://example.com", "issuanceDate": "2019-08-24T14:15:22Z", "issuer": "http://example.com", "proof": { "id": "string", "type": "string" }, "type": [ "string" ] }, "digest_multibase": "string", "holder": "http://example.com", "id": "http://example.com", "issuer": "http://example.com", "linked_credential_refs": [ { "blob_id": "http://example.com", "digest_multibase": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f" } ], "linked_file_refs": [ { "blob_id": "http://example.com", "digest_multibase": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f" } ], "type": [ "string" ], "valid_from": "2019-08-24T14:15:22Z", "valid_until": "2019-08-24T14:15:22Z" }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 }` #### [](#tag/credentials/operation/CredentialHistory)Read Credential's history. History of the Credential's resources. ###### Authorizations: *ApiKey* ###### path Parameters | | | | ---------- | ------------------------------------------------------------------- | | idrequired | string<uuid>The ID of the resource. | ###### header Parameters | | | | ------------- | ----------------------------------------------------- | | If-None-Match | stringThe ETag of the latest version of the resource. | ##### Responses **200** Response with the history of Credential. **304** HTTP 304 - Not modified. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **404** The schema represents an HTTP "Not Found" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. get/credentials/{id}/revisions URL for header-protected customer communication. https://api.truvity.{zone}/credentials/{id}/revisions URL for cookie-protected customer communication. https://docs.truvity.com/api/credentials/{id}/revisions ##### Request samples * Go * Java * TypeScript Copy ##### Response samples * 200 * 400 * 401 * 403 * 404 * 429 * 500 * default Content type application/json Copy Expand all Collapse all `{ "items": [ { "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "data_model": { "flavor_name": "VC1_1", "expirationDate": "2019-08-24T14:15:22Z", "holder": "http://example.com", "id": "http://example.com", "issuanceDate": "2019-08-24T14:15:22Z", "issuer": "http://example.com", "proof": { "id": "string", "type": "string" }, "type": [ "string" ] }, "digest_multibase": "string", "holder": "http://example.com", "id": "http://example.com", "issuer": "http://example.com", "linked_credential_refs": [ { "blob_id": "http://example.com", "digest_multibase": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f" } ], "linked_file_refs": [ { "blob_id": "http://example.com", "digest_multibase": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f" } ], "type": [ "string" ], "valid_from": "2019-08-24T14:15:22Z", "valid_until": "2019-08-24T14:15:22Z" }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 } ] }` #### [](#tag/credentials/operation/CredentialRevision)Read the specific version of the Credential. Read the specific version of the Credential's resource. ###### Authorizations: *ApiKey* ###### path Parameters | | | | ---------------- | ----------------------------------------------------------------------------------------------------------- | | idrequired | string<uuid>The ID of the resource. | | revisionrequired | integer<int32>\[ 1 .. 999999 ]The revision of the resource. | ###### header Parameters | | | | ------------- | ----------------------------------------------------- | | If-None-Match | stringThe ETag of the latest version of the resource. | ##### Responses **200** The requested revision of the Credential. **304** HTTP 304 - Not modified. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **404** The schema represents an HTTP "Not Found" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. get/credentials/{id}/revisions/{revision} URL for header-protected customer communication. https://api.truvity.{zone}/credentials/{id}/revisions/{revision} URL for cookie-protected customer communication. https://docs.truvity.com/api/credentials/{id}/revisions/{revision} ##### Request samples * Go * Java * TypeScript Copy ##### Response samples * 200 * 400 * 401 * 403 * 404 * 429 * 500 * default Content type application/json Copy Expand all Collapse all `{ "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "data_model": { "flavor_name": "VC1_1", "expirationDate": "2019-08-24T14:15:22Z", "holder": "http://example.com", "id": "http://example.com", "issuanceDate": "2019-08-24T14:15:22Z", "issuer": "http://example.com", "proof": { "id": "string", "type": "string" }, "type": [ "string" ] }, "digest_multibase": "string", "holder": "http://example.com", "id": "http://example.com", "issuer": "http://example.com", "linked_credential_refs": [ { "blob_id": "http://example.com", "digest_multibase": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f" } ], "linked_file_refs": [ { "blob_id": "http://example.com", "digest_multibase": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f" } ], "type": [ "string" ], "valid_from": "2019-08-24T14:15:22Z", "valid_until": "2019-08-24T14:15:22Z" }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 }` #### [](#tag/credentials/operation/CredentialDownload)Download of Credential's blob. Download of Credential's blob. ###### Authorizations: *ApiKey* ###### path Parameters | | | | ---------------- | ----------------------------------------------------------------------------------------------------------- | | idrequired | string<uuid>The ID of the resource. | | revisionrequired | integer<int32>\[ 1 .. 999999 ]The revision of the resource. | ###### header Parameters | | | | ------------- | ----------------------------------------------------- | | If-None-Match | stringThe ETag of the latest version of the resource. | ##### Responses **200** The result of downloading of Credential's resource. **304** HTTP 304 - Not modified. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **404** The schema represents an HTTP "Not Found" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. get/credentials/{id}/revisions/{revision}/download URL for header-protected customer communication. https://api.truvity.{zone}/credentials/{id}/revisions/{revision}/download URL for cookie-protected customer communication. https://docs.truvity.com/api/credentials/{id}/revisions/{revision}/download ##### Request samples * Go * Java * TypeScript Copy ##### Response samples * 200 * 400 * 401 * 403 * 404 * 429 * 500 * default Content type application/vc+ld+json Copy `"string"` #### [](#tag/credentials/operation/GetCredentialClaimValues)Get Credential Claim Values. Retrieve the claim values of a Verifiable Credential. ###### Authorizations: *ApiKey* ###### path Parameters | | | | ---------- | ------------------------------------------------------------------------------ | | idrequired | string<uuid>The ID of the credential resource. | ##### Responses **200** The claim values of the credential. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **404** The schema represents an HTTP "Not Found" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. get/credentials/{id}/values URL for header-protected customer communication. https://api.truvity.{zone}/credentials/{id}/values URL for cookie-protected customer communication. https://docs.truvity.com/api/credentials/{id}/values ##### Request samples * Go * Java * TypeScript Copy ##### Response samples * 200 * 400 * 401 * 403 * 404 * 429 * 500 * default Content type application/vnd.truvity.credential-claim-values+json;version=1 Copy Expand all Collapse all `{ "property1": { "kind": "STRING", "value": "string" }, "property2": { "kind": "STRING", "value": "string" } }` #### [](#tag/credentials/operation/CredentialVerify)Verify Credential. Verify a Verifiable Credential. ###### Authorizations: *ApiKey* ###### path Parameters | | | | ---------- | ------------------------------------------------------------------- | | idrequired | string<uuid>The ID of the resource. | ##### Responses **200** The verification result. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. get/credentials/{id}/verify URL for header-protected customer communication. https://api.truvity.{zone}/credentials/{id}/verify URL for cookie-protected customer communication. https://docs.truvity.com/api/credentials/{id}/verify ##### Request samples * Go * Java * TypeScript Copy ##### Response samples * 200 * 400 * 401 * 403 * 429 * 500 * default Content type application/json Copy `{ "verified": true }` #### [](#tag/desk)Desk The API to manage DID Documents and to receive DIDComm messages. #### [](#tag/desk/operation/PublishedJsonSchemaFetch)Get JSON Schema by slug and version. Get the published JSON Schema for a given slug and version. The slug is the unique identifier for the schema, and the version is the specific version of the schema. ###### Authorizations: *ApiKey* ###### path Parameters | | | | ------------------ | -------------------------------------------------------------------------------------------------------------------------- | | tenant\_idrequired | string<uuid>The ID of the tenant. | | slugrequired | string\[ 1 .. 256 ] characters^(?:\[a-zA-Z]\[a-zA-Z0-9]\*)(?:-\[a-zA-Z0-9]+)\*$Slug of a CredentialSchema. | | versionrequired | integer<int64>\[ 1 .. 99999 ]The version of the resource. | ##### Responses **200** The published JSON Schema. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **404** The schema represents an HTTP "Not Found" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. get/tenants/{tenant\_id}/json-schema/{slug}/v{version} URL for header-protected customer communication. https://api.truvity.{zone}/tenants/{tenant\_id}/json-schema/{slug}/v{version} URL for cookie-protected customer communication. https://docs.truvity.com/api/tenants/{tenant\_id}/json-schema/{slug}/v{version} ##### Response samples * 200 * 400 * 401 * 403 * 404 * 429 * 500 * default Content type application/schema+json Copy `{ }` #### [](#tag/desk/operation/PublishedMetaSchemaFetch)ExperimentalGet Meta Schema by slug and version. Get the published Meta Schema for a given slug and version. The slug is the unique identifier for the schema. ###### Authorizations: *ApiKey* ###### path Parameters | | | | ------------------ | -------------------------------------------------------------------------------------------------------------------------- | | tenant\_idrequired | string<uuid>The ID of the tenant. | | slugrequired | string\[ 1 .. 256 ] characters^(?:\[a-zA-Z]\[a-zA-Z0-9]\*)(?:-\[a-zA-Z0-9]+)\*$Slug of a CredentialSchema. | | versionrequired | integer<int64>\[ 1 .. 99999 ]The version of the resource. | ##### Responses **200** The published Meta Schema. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **404** The schema represents an HTTP "Not Found" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. get/tenants/{tenant\_id}/meta-schema/{slug}/v{version} URL for header-protected customer communication. https://api.truvity.{zone}/tenants/{tenant\_id}/meta-schema/{slug}/v{version} URL for cookie-protected customer communication. https://docs.truvity.com/api/tenants/{tenant\_id}/meta-schema/{slug}/v{version} ##### Response samples * 200 * 400 * 401 * 403 * 404 * 429 * 500 * default Content type application/json Copy Expand all Collapse all `{ "digest_multibase": "string", "json_ld_vocab_digest_multibase": "string", "json_ld_vocab_url": "http://example.com", "json_schema_digest_multibase": "string", "json_schema_url": "http://example.com", "published_at": "2019-08-24T14:15:22Z", "schema": { "fields": [ { "kind": "BOOLEAN", "is_array": true, "json_ld_iri": "string", "json_ld_type": "string", "name": "string", "not_empty": true, "title": "string" } ], "json_ld_base_iri": "string", "json_ld_iri": "string", "json_ld_relative_iri_delimiter": "string", "json_ld_term_name": "string" }, "slug": "string", "url": "http://example.com", "vcdm_json_schema_digest_multibase": "string", "vcdm_json_schema_url": "http://example.com", "version": 1 }` #### [](#tag/desk/operation/PublishedVcdmJsonSchemaFetch)Get VCDM JSON Schema by slug and version. Get the published VCDM JSON Schema for a given slug and version. The slug is the unique identifier for the schema, and the version is the specific version of the schema. ###### Authorizations: *ApiKey* ###### path Parameters | | | | ------------------ | -------------------------------------------------------------------------------------------------------------------------- | | tenant\_idrequired | string<uuid>The ID of the tenant. | | slugrequired | string\[ 1 .. 256 ] characters^(?:\[a-zA-Z]\[a-zA-Z0-9]\*)(?:-\[a-zA-Z0-9]+)\*$Slug of a CredentialSchema. | | versionrequired | integer<int64>\[ 1 .. 99999 ]The version of the resource. | ##### Responses **200** The published VCDM JSON Schema. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **404** The schema represents an HTTP "Not Found" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. get/tenants/{tenant\_id}/vc-json-schema/{slug}/v{version} URL for header-protected customer communication. https://api.truvity.{zone}/tenants/{tenant\_id}/vc-json-schema/{slug}/v{version} URL for cookie-protected customer communication. https://docs.truvity.com/api/tenants/{tenant\_id}/vc-json-schema/{slug}/v{version} ##### Response samples * 200 * 400 * 401 * 403 * 404 * 429 * 500 * default Content type application/schema+json Copy `{ }` #### [](#tag/desk/operation/PublishedJsonLdVocabFetch)Get JSON-LD Vocab by slug and version. Get the published JSON-LD Vocab for a given slug and version. The slug is the unique identifier for the schema, and the version is the specific version of the schema. ###### Authorizations: *ApiKey* ###### path Parameters | | | | ------------------ | -------------------------------------------------------------------------------------------------------------------------- | | tenant\_idrequired | string<uuid>The ID of the tenant. | | slugrequired | string\[ 1 .. 256 ] characters^(?:\[a-zA-Z]\[a-zA-Z0-9]\*)(?:-\[a-zA-Z0-9]+)\*$Slug of a CredentialSchema. | | versionrequired | integer<int64>\[ 1 .. 99999 ]The version of the resource. | ##### Responses **200** The published JSON-LD Vocab. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **404** The schema represents an HTTP "Not Found" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. get/tenants/{tenant\_id}/vocab/{slug}/v{version} URL for header-protected customer communication. https://api.truvity.{zone}/tenants/{tenant\_id}/vocab/{slug}/v{version} URL for cookie-protected customer communication. https://docs.truvity.com/api/tenants/{tenant\_id}/vocab/{slug}/v{version} ##### Response samples * 200 * 400 * 401 * 403 * 404 * 429 * 500 * default Content type application/ld+json Copy `{ }` #### [](#tag/desk/operation/DIDDocumentGet)Get DID-Document. Get DID-Document for [did:web Method Specification](https://w3c-ccg.github.io/did-method-web/). ###### path Parameters | | | | ------------------ | ----------------------------------------------------------------- | | tenant\_idrequired | string<uuid>The ID of the tenant. | ###### header Parameters | | | | ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | If-None-Match | stringFrom [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **If-None-Match header** field is used to declare a list of identifiers that are required to fail matching all the current resource version identifiers as a pre-condition for executing the request on the server side. This is especially used in conjunction with an **\*** (asterix) that is matching all possible resource identifiers to ensure the initial creation of a resource. Other use cases are possible but rare.If the pre-condition fails the server will respond with status code **412** (Precondition Failed). See [RFC 9110 Section 13.1.2](https://tools.ietf.org/html/rfc9110#section-13.1.2) as well as \[API Guideline Rule #182]\[api-182] for further details.\[api-182]: . | ##### Responses **200** DID Document according to [Decentralized Identifiers (DIDs) v1.0](https://www.w3.org/TR/did-core/). **400** The schema represents an HTTP "Bad Request" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. get/{tenant\_id}/did.json URL for header-protected customer communication. https://api.truvity.{zone}/{tenant\_id}/did.json URL for cookie-protected customer communication. https://docs.truvity.com/api/{tenant\_id}/did.json ##### Request samples * Go * Java * TypeScript Copy ##### Response samples * 200 * 400 * 429 * 500 * default Content type application/did+ld+json Copy Expand all Collapse all `{ "@context": [ "string" ], "assertionMethod": [ "strings" ], "authentication": [ "strings" ], "id": "strings", "service": [ { "id": "strings", "serviceEndpoint": "http://example.com", "type": "string" } ], "verificationMethod": [ { "@context": [ "string" ], "controller": "strings", "id": "strings", "publicKeyBase58": "string", "type": "Multikey" } ] }` #### [](#tag/desk/operation/DIDCommMessageRecv)Receive DIDComm Message. Receive DIDComm Message. ###### path Parameters | | | | ------------------ | ----------------------------------------------------------------- | | tenant\_idrequired | string<uuid>The ID of the tenant. | ###### Request Body schema: application/didcomm-signed+jsonrequired string < binary \> < application/octet-stream \> ##### Responses **202** HTTP 202 - Accepted. **400** The schema represents an HTTP "Bad Request" status code. **415** The schema represents an HTTP "Unsupported Media Type" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. post/{tenant\_id}/didcomm-messages/recv URL for header-protected customer communication. https://api.truvity.{zone}/{tenant\_id}/didcomm-messages/recv URL for cookie-protected customer communication. https://docs.truvity.com/api/{tenant\_id}/didcomm-messages/recv ##### Request samples * Payload * Go * Java * TypeScript Content type application/didcomm-signed+json Copy `"string"` ##### Response samples * 400 * 415 * 500 * default Content type application/problem+json Example /bad-request/bad-request Copy Expand all Collapse all `{ "detail": "string", "errors": [ { "location": "string", "message": "string", "value": null } ], "instance": "http://example.com", "status": 100, "title": "string", "type": "/bad-request" }` #### [](#tag/didcomm-messages)DIDComm Message The API to manage DIDComm messages. #### [](#tag/didcomm-messages/operation/DidcommMessageSearch)Search for DIDComm Messages. Search for DIDComm Messages with extended filters capabilities. ###### Authorizations: *ApiKey* ###### Request Body schema: application/jsonrequired | | | | ------ | --------------------------------------------------------------------------------------------------------------------- | | filter | Array of objects (DidcommMessageFilter)<= 4 itemsThe filter to apply to the search. | | sort | Array of objects (DidcommMessageSort)<= 4 itemsThe sort order to apply to the search. | ##### Responses **200** The search results of DIDComm Message. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **415** The schema represents an HTTP "Unsupported Media Type" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. post/didcomm-messages/search URL for header-protected customer communication. https://api.truvity.{zone}/didcomm-messages/search URL for cookie-protected customer communication. https://docs.truvity.com/api/didcomm-messages/search ##### Request samples * Payload * Go * Java * TypeScript Content type application/json Copy Expand all Collapse all `{ "filter": [ { "annotations": [ { "operator": "EQUAL", "key": "string", "value": "string" } ], "created_at": { "operator": "BETWEEN", "left": "2019-08-24T14:15:22Z", "right": "2019-08-24T14:15:22Z" }, "data": { "credentials": { "operator": "IN", "values": [ "497f6eca-6276-4993-bfeb-53cbbbba6f08" ] }, "from": { "operator": "EQUAL", "value": "strings" }, "presentations": { "operator": "IN", "values": [ "497f6eca-6276-4993-bfeb-53cbbbba6f08" ] }, "to": { "operator": "EQUAL", "value": "strings" } }, "deleted_at": { "operator": "BETWEEN", "left": "2019-08-24T14:15:22Z", "right": "2019-08-24T14:15:22Z" }, "etag": { "operator": "EQUAL", "value": "string" }, "id": { "operator": "EQUAL", "value": "a860a344-d7b2-406e-828e-8d442f23f344" }, "labels": [ { "operator": "EQUAL", "key": "string", "value": "string" } ], "modified_at": { "operator": "BETWEEN", "left": "2019-08-24T14:15:22Z", "right": "2019-08-24T14:15:22Z" }, "revision": { "operator": "EQUAL", "value": 1 } } ], "sort": [ { "field": "DATA_FROM", "order": "ASC" } ] }` ##### Response samples * 200 * 400 * 401 * 403 * 415 * 429 * 500 * default Content type application/json Copy Expand all Collapse all `{ "items": [ { "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "credentials": { "items": [ { "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "data_model": { "flavor_name": "VC1_1", "expirationDate": "2019-08-24T14:15:22Z", "holder": "http://example.com", "id": "http://example.com", "issuanceDate": "2019-08-24T14:15:22Z", "issuer": "http://example.com", "proof": { "id": null, "type": null }, "type": [ null ] }, "digest_multibase": "string", "holder": "http://example.com", "id": "http://example.com", "issuer": "http://example.com", "linked_credential_refs": [ { "blob_id": null, "digest_multibase": null, "resource_id": null } ], "linked_file_refs": [ { "blob_id": null, "digest_multibase": null, "resource_id": null } ], "type": [ "string" ], "valid_from": "2019-08-24T14:15:22Z", "valid_until": "2019-08-24T14:15:22Z" }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 } ] }, "files": { "items": [ { "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "content_type": "string", "digest_multibase": "string", "filename": "string", "filesize": 1, "id": "http://example.com" }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 } ] }, "from": "strings", "presentations": { "items": [ { "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "digest_multibase": "string", "id": "http://example.com", "linked_credential_refs": [ { "blob_id": null, "digest_multibase": null, "resource_id": null } ], "type": [ "string" ] }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 } ] }, "to": "strings" }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 } ] }` #### [](#tag/didcomm-messages/operation/DIDCommMessageSend)Send a DIDComm Message. Send a DIDComm Message to a recipient. ###### Authorizations: *ApiKey* ###### header Parameters | | | | --------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Idempotency-Key | string\[ 32 .. 256 ] characters\[a-zA-Z0-9-]{32,256}From [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **Idempotency-Key** is a free identifier created by the client to identify a request. It is used by the service to identify repeated request to ensure idempotent behavior by sending the same (or a similar) response without executing the request a second time.Clients should be careful as any subsequent requests with the same key may return the same response without further check. Thus, it is recommended to use a UUID version 4 (random) or any other random string with enough entropy to avoid collisions.Keys expire after 24 hours. Clients are responsible to stay within this limit, if they require idempotent behavior.See [API Guideline Rule #181](https://opensource.zalando.com/restful-api-guidelines/#230) for further details. | ###### Request Body schema: application/jsonrequired | | | | ------------ | --------------------------------------------------------------------------------- | | annotations | objectThe annotations of the resource. | | datarequired | object (DIDCommMessageSend)The request to send a DIDComm message. | | labels | objectThe labels of the resource. | ##### Responses **201** The sent DIDComm Message to a recipient. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **404** The schema represents an HTTP "Not Found" status code. **405** The schema represents an HTTP "Method Not Allowed" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. post/didcomm-messages/send URL for header-protected customer communication. https://api.truvity.{zone}/didcomm-messages/send URL for cookie-protected customer communication. https://docs.truvity.com/api/didcomm-messages/send ##### Request samples * Payload * Go * Java * TypeScript Content type application/json Copy Expand all Collapse all `{ "annotations": { "property1": "string", "property2": "string" }, "data": { "credentials": [ "497f6eca-6276-4993-bfeb-53cbbbba6f08" ], "disable_transitive_closure": true, "files": [ "497f6eca-6276-4993-bfeb-53cbbbba6f08" ], "key_id": "1e779c8a-6786-4c89-b7c3-a6666f5fd6b5", "presentations": [ "497f6eca-6276-4993-bfeb-53cbbbba6f08" ], "to": "strings" }, "labels": { "property1": "string", "property2": "string" } }` ##### Response samples * 201 * 400 * 401 * 403 * 404 * 405 * 429 * 500 * default Content type application/vnd.truvity.didcomm-message+json;version=1 Copy Expand all Collapse all `{ "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "credentials": { "items": [ { "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "data_model": { "flavor_name": "VC1_1", "expirationDate": "2019-08-24T14:15:22Z", "holder": "http://example.com", "id": "http://example.com", "issuanceDate": "2019-08-24T14:15:22Z", "issuer": "http://example.com", "proof": { "id": "string", "type": "string" }, "type": [ "string" ] }, "digest_multibase": "string", "holder": "http://example.com", "id": "http://example.com", "issuer": "http://example.com", "linked_credential_refs": [ { "blob_id": "http://example.com", "digest_multibase": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f" } ], "linked_file_refs": [ { "blob_id": "http://example.com", "digest_multibase": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f" } ], "type": [ "string" ], "valid_from": "2019-08-24T14:15:22Z", "valid_until": "2019-08-24T14:15:22Z" }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 } ] }, "files": { "items": [ { "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "content_type": "string", "digest_multibase": "string", "filename": "string", "filesize": 1, "id": "http://example.com" }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 } ] }, "from": "strings", "presentations": { "items": [ { "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "digest_multibase": "string", "id": "http://example.com", "linked_credential_refs": [ { "blob_id": "http://example.com", "digest_multibase": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f" } ], "type": [ "string" ] }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 } ] }, "to": "strings" }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 }` #### [](#tag/didcomm-messages/operation/DidcommMessageDelete)Delete DIDComm Message. Delete DIDComm Message's resource. ###### Authorizations: *ApiKey* ###### path Parameters | | | | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | idrequired | string<uuid>The primary and unique identifier of the resource (inside tenant) according to [RFC 4122](https://www.rfc-editor.org/info/rfc4122). | ###### header Parameters | | | | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Idempotency-Key | string\[ 32 .. 256 ] characters\[a-zA-Z0-9-]{32,256}From [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **Idempotency-Key** is a free identifier created by the client to identify a request. It is used by the service to identify repeated request to ensure idempotent behavior by sending the same (or a similar) response without executing the request a second time.Clients should be careful as any subsequent requests with the same key may return the same response without further check. Thus, it is recommended to use a UUID version 4 (random) or any other random string with enough entropy to avoid collisions.Keys expire after 24 hours. Clients are responsible to stay within this limit, if they require idempotent behavior.See [API Guideline Rule #181](https://opensource.zalando.com/restful-api-guidelines/#230) for further details. | | If-Matchrequired | stringFrom [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **If-Match** header field is used to declare a list of identifiers that are required to match the current resource version identifier in at least one position as a pre-condition for executing the request on the server side. This behavior is used to validate and reject optimistic updates, by checking if the resource version a consumer has based his changes on is outdated on arrival of the change request to prevent lost updates.If the pre-condition fails the server will respond with status code **412** (Precondition Failed). See [RFC 9110 Section 13.1.1](https://tools.ietf.org/html/rfc9110#section-13.1.1) as well as \[API Guideline Rule #182]\[api-182] for further details.\[api-182]: . | ##### Responses **204** HTTP 204 - No content. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **404** The schema represents an HTTP "Not Found" status code. **405** The schema represents an HTTP "Method Not Allowed" status code. **412** The schema represents an HTTP "Precondition Failed" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. delete/didcomm-messages/{id} URL for header-protected customer communication. https://api.truvity.{zone}/didcomm-messages/{id} URL for cookie-protected customer communication. https://docs.truvity.com/api/didcomm-messages/{id} ##### Request samples * Go * Java * TypeScript Copy ##### Response samples * 400 * 401 * 403 * 404 * 405 * 412 * 429 * 500 * default Content type application/problem+json Example /bad-request/bad-request Copy Expand all Collapse all `{ "detail": "string", "errors": [ { "location": "string", "message": "string", "value": null } ], "instance": "http://example.com", "status": 100, "title": "string", "type": "/bad-request" }` #### [](#tag/didcomm-messages/operation/DidcommMessageLatest)Get the latest version of DIDComm Message. Get the latest version of DIDComm Message. ###### Authorizations: *ApiKey* ###### path Parameters | | | | ---------- | ------------------------------------------------------------------- | | idrequired | string<uuid>The ID of the resource. | ###### header Parameters | | | | ------------- | ----------------------------------------------------- | | If-None-Match | stringThe ETag of the latest version of the resource. | ##### Responses **200** Response with the latest DIDComm Message. **304** HTTP 304 - Not modified. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **404** The schema represents an HTTP "Not Found" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. get/didcomm-messages/{id} URL for header-protected customer communication. https://api.truvity.{zone}/didcomm-messages/{id} URL for cookie-protected customer communication. https://docs.truvity.com/api/didcomm-messages/{id} ##### Request samples * Go * Java * TypeScript Copy ##### Response samples * 200 * 400 * 401 * 403 * 404 * 429 * 500 * default Content type application/vnd.truvity.didcomm-message+json;version=1 Copy Expand all Collapse all `{ "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "credentials": { "items": [ { "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "data_model": { "flavor_name": "VC1_1", "expirationDate": "2019-08-24T14:15:22Z", "holder": "http://example.com", "id": "http://example.com", "issuanceDate": "2019-08-24T14:15:22Z", "issuer": "http://example.com", "proof": { "id": "string", "type": "string" }, "type": [ "string" ] }, "digest_multibase": "string", "holder": "http://example.com", "id": "http://example.com", "issuer": "http://example.com", "linked_credential_refs": [ { "blob_id": "http://example.com", "digest_multibase": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f" } ], "linked_file_refs": [ { "blob_id": "http://example.com", "digest_multibase": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f" } ], "type": [ "string" ], "valid_from": "2019-08-24T14:15:22Z", "valid_until": "2019-08-24T14:15:22Z" }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 } ] }, "files": { "items": [ { "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "content_type": "string", "digest_multibase": "string", "filename": "string", "filesize": 1, "id": "http://example.com" }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 } ] }, "from": "strings", "presentations": { "items": [ { "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "digest_multibase": "string", "id": "http://example.com", "linked_credential_refs": [ { "blob_id": "http://example.com", "digest_multibase": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f" } ], "type": [ "string" ] }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 } ] }, "to": "strings" }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 }` #### [](#tag/didcomm-messages/operation/DidcommMessageUpdateAnnotations)Update annotations. Update annotations of DIDComm Message's resource. ###### Authorizations: *ApiKey* ###### path Parameters | | | | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | idrequired | string<uuid>The primary and unique identifier of the resource (inside tenant) according to [RFC 4122](https://www.rfc-editor.org/info/rfc4122). | ###### header Parameters | | | | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Idempotency-Key | string\[ 32 .. 256 ] characters\[a-zA-Z0-9-]{32,256}From [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **Idempotency-Key** is a free identifier created by the client to identify a request. It is used by the service to identify repeated request to ensure idempotent behavior by sending the same (or a similar) response without executing the request a second time.Clients should be careful as any subsequent requests with the same key may return the same response without further check. Thus, it is recommended to use a UUID version 4 (random) or any other random string with enough entropy to avoid collisions.Keys expire after 24 hours. Clients are responsible to stay within this limit, if they require idempotent behavior.See [API Guideline Rule #181](https://opensource.zalando.com/restful-api-guidelines/#230) for further details. | | If-Matchrequired | stringFrom [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **If-Match** header field is used to declare a list of identifiers that are required to match the current resource version identifier in at least one position as a pre-condition for executing the request on the server side. This behavior is used to validate and reject optimistic updates, by checking if the resource version a consumer has based his changes on is outdated on arrival of the change request to prevent lost updates.If the pre-condition fails the server will respond with status code **412** (Precondition Failed). See [RFC 9110 Section 13.1.1](https://tools.ietf.org/html/rfc9110#section-13.1.1) as well as \[API Guideline Rule #182]\[api-182] for further details.\[api-182]: . | ###### Request Body schema: application/jsonrequired | | | | ----------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------- | | annotationsrequired | objectThe annotations of the resource. | | property name\* additional property string <= 128 characters ^\[^\n]{0,128}$ Value of the resource annotation. | | ##### Responses **200** Response with the updated DIDComm Message. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **404** The schema represents an HTTP "Not Found" status code. **405** The schema represents an HTTP "Method Not Allowed" status code. **412** The schema represents an HTTP "Precondition Failed" status code. **415** The schema represents an HTTP "Unsupported Media Type" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. patch/didcomm-messages/{id}/annotations URL for header-protected customer communication. https://api.truvity.{zone}/didcomm-messages/{id}/annotations URL for cookie-protected customer communication. https://docs.truvity.com/api/didcomm-messages/{id}/annotations ##### Request samples * Payload * Go * Java * TypeScript Content type application/json Copy Expand all Collapse all `{ "annotations": { "property1": "string", "property2": "string" } }` ##### Response samples * 200 * 400 * 401 * 403 * 404 * 405 * 412 * 415 * 429 * 500 * default Content type application/vnd.truvity.didcomm-message+json;version=1 Copy Expand all Collapse all `{ "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "credentials": { "items": [ { "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "data_model": { "flavor_name": "VC1_1", "expirationDate": "2019-08-24T14:15:22Z", "holder": "http://example.com", "id": "http://example.com", "issuanceDate": "2019-08-24T14:15:22Z", "issuer": "http://example.com", "proof": { "id": "string", "type": "string" }, "type": [ "string" ] }, "digest_multibase": "string", "holder": "http://example.com", "id": "http://example.com", "issuer": "http://example.com", "linked_credential_refs": [ { "blob_id": "http://example.com", "digest_multibase": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f" } ], "linked_file_refs": [ { "blob_id": "http://example.com", "digest_multibase": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f" } ], "type": [ "string" ], "valid_from": "2019-08-24T14:15:22Z", "valid_until": "2019-08-24T14:15:22Z" }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 } ] }, "files": { "items": [ { "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "content_type": "string", "digest_multibase": "string", "filename": "string", "filesize": 1, "id": "http://example.com" }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 } ] }, "from": "strings", "presentations": { "items": [ { "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "digest_multibase": "string", "id": "http://example.com", "linked_credential_refs": [ { "blob_id": "http://example.com", "digest_multibase": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f" } ], "type": [ "string" ] }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 } ] }, "to": "strings" }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 }` #### [](#tag/didcomm-messages/operation/DidcommMessageUpdateLabels)Update labels. Update labels of DIDComm Message's resource. ###### Authorizations: *ApiKey* ###### path Parameters | | | | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | idrequired | string<uuid>The primary and unique identifier of the resource (inside tenant) according to [RFC 4122](https://www.rfc-editor.org/info/rfc4122). | ###### header Parameters | | | | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Idempotency-Key | string\[ 32 .. 256 ] characters\[a-zA-Z0-9-]{32,256}From [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **Idempotency-Key** is a free identifier created by the client to identify a request. It is used by the service to identify repeated request to ensure idempotent behavior by sending the same (or a similar) response without executing the request a second time.Clients should be careful as any subsequent requests with the same key may return the same response without further check. Thus, it is recommended to use a UUID version 4 (random) or any other random string with enough entropy to avoid collisions.Keys expire after 24 hours. Clients are responsible to stay within this limit, if they require idempotent behavior.See [API Guideline Rule #181](https://opensource.zalando.com/restful-api-guidelines/#230) for further details. | | If-Matchrequired | stringFrom [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **If-Match** header field is used to declare a list of identifiers that are required to match the current resource version identifier in at least one position as a pre-condition for executing the request on the server side. This behavior is used to validate and reject optimistic updates, by checking if the resource version a consumer has based his changes on is outdated on arrival of the change request to prevent lost updates.If the pre-condition fails the server will respond with status code **412** (Precondition Failed). See [RFC 9110 Section 13.1.1](https://tools.ietf.org/html/rfc9110#section-13.1.1) as well as \[API Guideline Rule #182]\[api-182] for further details.\[api-182]: . | ###### Request Body schema: application/jsonrequired | | | | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------- | | labelsrequired | objectThe labels of the resource. | | property name\* additional property string <= 63 characters ^(?:\[a-zA-Z0-9]\(?:\[a-zA-Z0-9\\.\\-\_]{0,61}\[a-zA...Show pattern Value of the resource label. | | ##### Responses **200** Response with the updated DIDComm Message. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **404** The schema represents an HTTP "Not Found" status code. **405** The schema represents an HTTP "Method Not Allowed" status code. **412** The schema represents an HTTP "Precondition Failed" status code. **415** The schema represents an HTTP "Unsupported Media Type" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. patch/didcomm-messages/{id}/labels URL for header-protected customer communication. https://api.truvity.{zone}/didcomm-messages/{id}/labels URL for cookie-protected customer communication. https://docs.truvity.com/api/didcomm-messages/{id}/labels ##### Request samples * Payload * Go * Java * TypeScript Content type application/json Copy Expand all Collapse all `{ "labels": { "property1": "string", "property2": "string" } }` ##### Response samples * 200 * 400 * 401 * 403 * 404 * 405 * 412 * 415 * 429 * 500 * default Content type application/vnd.truvity.didcomm-message+json;version=1 Copy Expand all Collapse all `{ "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "credentials": { "items": [ { "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "data_model": { "flavor_name": "VC1_1", "expirationDate": "2019-08-24T14:15:22Z", "holder": "http://example.com", "id": "http://example.com", "issuanceDate": "2019-08-24T14:15:22Z", "issuer": "http://example.com", "proof": { "id": "string", "type": "string" }, "type": [ "string" ] }, "digest_multibase": "string", "holder": "http://example.com", "id": "http://example.com", "issuer": "http://example.com", "linked_credential_refs": [ { "blob_id": "http://example.com", "digest_multibase": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f" } ], "linked_file_refs": [ { "blob_id": "http://example.com", "digest_multibase": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f" } ], "type": [ "string" ], "valid_from": "2019-08-24T14:15:22Z", "valid_until": "2019-08-24T14:15:22Z" }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 } ] }, "files": { "items": [ { "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "content_type": "string", "digest_multibase": "string", "filename": "string", "filesize": 1, "id": "http://example.com" }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 } ] }, "from": "strings", "presentations": { "items": [ { "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "digest_multibase": "string", "id": "http://example.com", "linked_credential_refs": [ { "blob_id": "http://example.com", "digest_multibase": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f" } ], "type": [ "string" ] }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 } ] }, "to": "strings" }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 }` #### [](#tag/didcomm-messages/operation/DidcommMessageRestore)Restore DIDComm Message. Restore DIDComm Message's resource. ###### Authorizations: *ApiKey* ###### path Parameters | | | | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | idrequired | string<uuid>The primary and unique identifier of the resource (inside tenant) according to [RFC 4122](https://www.rfc-editor.org/info/rfc4122). | ###### header Parameters | | | | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Idempotency-Key | string\[ 32 .. 256 ] characters\[a-zA-Z0-9-]{32,256}From [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **Idempotency-Key** is a free identifier created by the client to identify a request. It is used by the service to identify repeated request to ensure idempotent behavior by sending the same (or a similar) response without executing the request a second time.Clients should be careful as any subsequent requests with the same key may return the same response without further check. Thus, it is recommended to use a UUID version 4 (random) or any other random string with enough entropy to avoid collisions.Keys expire after 24 hours. Clients are responsible to stay within this limit, if they require idempotent behavior.See [API Guideline Rule #181](https://opensource.zalando.com/restful-api-guidelines/#230) for further details. | | If-Matchrequired | stringFrom [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **If-Match** header field is used to declare a list of identifiers that are required to match the current resource version identifier in at least one position as a pre-condition for executing the request on the server side. This behavior is used to validate and reject optimistic updates, by checking if the resource version a consumer has based his changes on is outdated on arrival of the change request to prevent lost updates.If the pre-condition fails the server will respond with status code **412** (Precondition Failed). See [RFC 9110 Section 13.1.1](https://tools.ietf.org/html/rfc9110#section-13.1.1) as well as \[API Guideline Rule #182]\[api-182] for further details.\[api-182]: . | ##### Responses **200** Response with the restored DIDComm Message. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **404** The schema represents an HTTP "Not Found" status code. **405** The schema represents an HTTP "Method Not Allowed" status code. **412** The schema represents an HTTP "Precondition Failed" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. post/didcomm-messages/{id}/restore URL for header-protected customer communication. https://api.truvity.{zone}/didcomm-messages/{id}/restore URL for cookie-protected customer communication. https://docs.truvity.com/api/didcomm-messages/{id}/restore ##### Request samples * Go * Java * TypeScript Copy ##### Response samples * 200 * 400 * 401 * 403 * 404 * 405 * 412 * 429 * 500 * default Content type application/vnd.truvity.didcomm-message+json;version=1 Copy Expand all Collapse all `{ "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "credentials": { "items": [ { "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "data_model": { "flavor_name": "VC1_1", "expirationDate": "2019-08-24T14:15:22Z", "holder": "http://example.com", "id": "http://example.com", "issuanceDate": "2019-08-24T14:15:22Z", "issuer": "http://example.com", "proof": { "id": "string", "type": "string" }, "type": [ "string" ] }, "digest_multibase": "string", "holder": "http://example.com", "id": "http://example.com", "issuer": "http://example.com", "linked_credential_refs": [ { "blob_id": "http://example.com", "digest_multibase": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f" } ], "linked_file_refs": [ { "blob_id": "http://example.com", "digest_multibase": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f" } ], "type": [ "string" ], "valid_from": "2019-08-24T14:15:22Z", "valid_until": "2019-08-24T14:15:22Z" }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 } ] }, "files": { "items": [ { "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "content_type": "string", "digest_multibase": "string", "filename": "string", "filesize": 1, "id": "http://example.com" }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 } ] }, "from": "strings", "presentations": { "items": [ { "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "digest_multibase": "string", "id": "http://example.com", "linked_credential_refs": [ { "blob_id": "http://example.com", "digest_multibase": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f" } ], "type": [ "string" ] }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 } ] }, "to": "strings" }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 }` #### [](#tag/didcomm-messages/operation/DidcommMessageHistory)Read DIDComm Message's history. History of the DIDComm Message's resources. ###### Authorizations: *ApiKey* ###### path Parameters | | | | ---------- | ------------------------------------------------------------------- | | idrequired | string<uuid>The ID of the resource. | ###### header Parameters | | | | ------------- | ----------------------------------------------------- | | If-None-Match | stringThe ETag of the latest version of the resource. | ##### Responses **200** Response with the history of DIDComm Message. **304** HTTP 304 - Not modified. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **404** The schema represents an HTTP "Not Found" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. get/didcomm-messages/{id}/revisions URL for header-protected customer communication. https://api.truvity.{zone}/didcomm-messages/{id}/revisions URL for cookie-protected customer communication. https://docs.truvity.com/api/didcomm-messages/{id}/revisions ##### Request samples * Go * Java * TypeScript Copy ##### Response samples * 200 * 400 * 401 * 403 * 404 * 429 * 500 * default Content type application/json Copy Expand all Collapse all `{ "items": [ { "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "credentials": { "items": [ { "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "data_model": { "flavor_name": "VC1_1", "expirationDate": "2019-08-24T14:15:22Z", "holder": "http://example.com", "id": "http://example.com", "issuanceDate": "2019-08-24T14:15:22Z", "issuer": "http://example.com", "proof": { "id": null, "type": null }, "type": [ null ] }, "digest_multibase": "string", "holder": "http://example.com", "id": "http://example.com", "issuer": "http://example.com", "linked_credential_refs": [ { "blob_id": null, "digest_multibase": null, "resource_id": null } ], "linked_file_refs": [ { "blob_id": null, "digest_multibase": null, "resource_id": null } ], "type": [ "string" ], "valid_from": "2019-08-24T14:15:22Z", "valid_until": "2019-08-24T14:15:22Z" }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 } ] }, "files": { "items": [ { "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "content_type": "string", "digest_multibase": "string", "filename": "string", "filesize": 1, "id": "http://example.com" }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 } ] }, "from": "strings", "presentations": { "items": [ { "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "digest_multibase": "string", "id": "http://example.com", "linked_credential_refs": [ { "blob_id": null, "digest_multibase": null, "resource_id": null } ], "type": [ "string" ] }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 } ] }, "to": "strings" }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 } ] }` #### [](#tag/didcomm-messages/operation/DidcommMessageRevision)Read the specific version of the DIDComm Message. Read the specific version of the DIDComm Message's resource. ###### Authorizations: *ApiKey* ###### path Parameters | | | | ---------------- | ----------------------------------------------------------------------------------------------------------- | | idrequired | string<uuid>The ID of the resource. | | revisionrequired | integer<int32>\[ 1 .. 999999 ]The revision of the resource. | ###### header Parameters | | | | ------------- | ----------------------------------------------------- | | If-None-Match | stringThe ETag of the latest version of the resource. | ##### Responses **200** The requested revision of the DIDComm Message. **304** HTTP 304 - Not modified. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **404** The schema represents an HTTP "Not Found" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. get/didcomm-messages/{id}/revisions/{revision} URL for header-protected customer communication. https://api.truvity.{zone}/didcomm-messages/{id}/revisions/{revision} URL for cookie-protected customer communication. https://docs.truvity.com/api/didcomm-messages/{id}/revisions/{revision} ##### Request samples * Go * Java * TypeScript Copy ##### Response samples * 200 * 400 * 401 * 403 * 404 * 429 * 500 * default Content type application/json Copy Expand all Collapse all `{ "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "credentials": { "items": [ { "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "data_model": { "flavor_name": "VC1_1", "expirationDate": "2019-08-24T14:15:22Z", "holder": "http://example.com", "id": "http://example.com", "issuanceDate": "2019-08-24T14:15:22Z", "issuer": "http://example.com", "proof": { "id": "string", "type": "string" }, "type": [ "string" ] }, "digest_multibase": "string", "holder": "http://example.com", "id": "http://example.com", "issuer": "http://example.com", "linked_credential_refs": [ { "blob_id": "http://example.com", "digest_multibase": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f" } ], "linked_file_refs": [ { "blob_id": "http://example.com", "digest_multibase": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f" } ], "type": [ "string" ], "valid_from": "2019-08-24T14:15:22Z", "valid_until": "2019-08-24T14:15:22Z" }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 } ] }, "files": { "items": [ { "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "content_type": "string", "digest_multibase": "string", "filename": "string", "filesize": 1, "id": "http://example.com" }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 } ] }, "from": "strings", "presentations": { "items": [ { "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "digest_multibase": "string", "id": "http://example.com", "linked_credential_refs": [ { "blob_id": "http://example.com", "digest_multibase": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f" } ], "type": [ "string" ] }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 } ] }, "to": "strings" }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 }` #### [](#tag/dids)DIDs The API to manage DID Documents. #### [](#tag/dids/operation/DIDDocumentSelfGet)Return the tenant's DID(did:web) document. Return the tenant's DID(did:web) document. Comparing to [DIDDocumentGet](#tag/desk/operation/DIDDocumentGet) endpoint, this one returns the tenant's DID(did:web) document for the authenticated tenant only. ###### Authorizations: *ApiKey* ###### header Parameters | | | | ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | If-None-Match | stringFrom [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **If-None-Match header** field is used to declare a list of identifiers that are required to fail matching all the current resource version identifiers as a pre-condition for executing the request on the server side. This is especially used in conjunction with an **\*** (asterix) that is matching all possible resource identifiers to ensure the initial creation of a resource. Other use cases are possible but rare.If the pre-condition fails the server will respond with status code **412** (Precondition Failed). See [RFC 9110 Section 13.1.2](https://tools.ietf.org/html/rfc9110#section-13.1.2) as well as \[API Guideline Rule #182]\[api-182] for further details.\[api-182]: . | ##### Responses **200** Response with the tenant's DID(did:web) document. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. get/dids/self URL for header-protected customer communication. https://api.truvity.{zone}/dids/self URL for cookie-protected customer communication. https://docs.truvity.com/api/dids/self ##### Request samples * Go * Java * TypeScript Copy ##### Response samples * 200 * 400 * 401 * 403 * 429 * 500 * default Content type application/did+ld+json Copy Expand all Collapse all `{ "@context": [ "string" ], "assertionMethod": [ "strings" ], "authentication": [ "strings" ], "id": "strings", "service": [ { "id": "strings", "serviceEndpoint": "http://example.com", "type": "string" } ], "verificationMethod": [ { "@context": [ "string" ], "controller": "strings", "id": "strings", "publicKeyBase58": "string", "type": "Multikey" } ] }` #### [](#tag/drafts)Draft The API to manage Drafts. #### [](#tag/drafts/operation/DraftCreate)Create Draft. Creates Draft's resource. ###### Authorizations: *ApiKey* ###### header Parameters | | | | --------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Idempotency-Key | string\[ 32 .. 256 ] characters\[a-zA-Z0-9-]{32,256}From [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **Idempotency-Key** is a free identifier created by the client to identify a request. It is used by the service to identify repeated request to ensure idempotent behavior by sending the same (or a similar) response without executing the request a second time.Clients should be careful as any subsequent requests with the same key may return the same response without further check. Thus, it is recommended to use a UUID version 4 (random) or any other random string with enough entropy to avoid collisions.Keys expire after 24 hours. Clients are responsible to stay within this limit, if they require idempotent behavior.See [API Guideline Rule #181](https://opensource.zalando.com/restful-api-guidelines/#230) for further details. | ###### Request Body schema: application/jsonrequired | | | | ------------ | -------------------------------------------------------------------- | | annotations | objectThe annotations of the resource. | | datarequired | object (DraftCreate)The schema for creating a draft. | | labels | objectThe labels of the resource. | ##### Responses **201** Response with the newly created Draft. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **415** The schema represents an HTTP "Unsupported Media Type" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. post/drafts URL for header-protected customer communication. https://api.truvity.{zone}/drafts URL for cookie-protected customer communication. https://docs.truvity.com/api/drafts ##### Request samples * Payload * Go * Java * TypeScript Content type application/json Copy Expand all Collapse all `{ "annotations": { "property1": "string", "property2": "string" }, "data": { "json_ld_vocabs": [ "http://example.com" ], "meta": { "subject": "string", "valid_from": "2019-08-24T14:15:22Z", "valid_until": "2019-08-24T14:15:22Z" }, "meta_schema": { "schema": { "fields": [ { "kind": "BOOLEAN", "is_array": true, "json_ld_iri": "string", "json_ld_type": "string", "name": "string", "not_empty": true, "title": "string" } ], "json_ld_base_iri": "string", "json_ld_iri": "string", "json_ld_relative_iri_delimiter": "string", "json_ld_term_name": "string" }, "slug": "string", "version": 1 }, "values": { "property1": { "kind": "STRING", "value": "string" }, "property2": { "kind": "STRING", "value": "string" } }, "vcdm_json_schemas": [ "http://example.com" ] }, "labels": { "property1": "string", "property2": "string" } }` ##### Response samples * 201 * 400 * 401 * 403 * 415 * 429 * 500 * default Content type application/vnd.truvity.draft+json;version=1 Copy Expand all Collapse all `{ "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "json_ld_vocabs": [ "http://example.com" ], "linked_credential_refs": [ { "blob_id": "http://example.com", "digest_multibase": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f" } ], "linked_draft_refs": [ { "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f" } ], "meta": { "subject": "string", "valid_from": "2019-08-24T14:15:22Z", "valid_until": "2019-08-24T14:15:22Z" }, "meta_schema": "http://example.com", "type": [ "string" ], "values": { "property1": { "kind": "STRING", "value": "string" }, "property2": { "kind": "STRING", "value": "string" } }, "vcdm_json_schemas": [ "http://example.com" ] }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 }` #### [](#tag/drafts/operation/DraftSearch)Search for Drafts. Search for Drafts with extended filters capabilities. ###### Authorizations: *ApiKey* ###### Request Body schema: application/jsonrequired | | | | ------ | ------------------------------------------------------------------------------------------------------------ | | filter | Array of objects (DraftFilter)<= 4 itemsThe filter to apply to the search. | | sort | Array of objects (DraftSort)<= 4 itemsThe sort order to apply to the search. | ##### Responses **200** The search results of Draft. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **415** The schema represents an HTTP "Unsupported Media Type" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. post/drafts/search URL for header-protected customer communication. https://api.truvity.{zone}/drafts/search URL for cookie-protected customer communication. https://docs.truvity.com/api/drafts/search ##### Request samples * Payload * Go * Java * TypeScript Content type application/json Copy Expand all Collapse all `{ "filter": [ { "annotations": [ { "operator": "EQUAL", "key": "string", "value": "string" } ], "created_at": { "operator": "BETWEEN", "left": "2019-08-24T14:15:22Z", "right": "2019-08-24T14:15:22Z" }, "data": { "meta": { "subject": { "operator": "EQUAL", "value": "string" }, "valid_from": { "operator": "BETWEEN", "left": "2019-08-24T14:15:22Z", "right": "2019-08-24T14:15:22Z" }, "valid_until": { "operator": "BETWEEN", "left": "2019-08-24T14:15:22Z", "right": "2019-08-24T14:15:22Z" } }, "type": { "operator": "IN", "values": [ "string" ] } }, "deleted_at": { "operator": "BETWEEN", "left": "2019-08-24T14:15:22Z", "right": "2019-08-24T14:15:22Z" }, "etag": { "operator": "EQUAL", "value": "string" }, "id": { "operator": "EQUAL", "value": "a860a344-d7b2-406e-828e-8d442f23f344" }, "labels": [ { "operator": "EQUAL", "key": "string", "value": "string" } ], "modified_at": { "operator": "BETWEEN", "left": "2019-08-24T14:15:22Z", "right": "2019-08-24T14:15:22Z" }, "revision": { "operator": "EQUAL", "value": 1 }, "linked_credentials": { "annotations": [ { "operator": "EQUAL", "key": "string", "value": "string" } ], "created_at": { "operator": "BETWEEN", "left": "2019-08-24T14:15:22Z", "right": "2019-08-24T14:15:22Z" }, "data": { "digest_multibase": { "operator": "EQUAL", "value": "string" }, "holder": { "operator": "EQUAL", "value": "http://example.com" }, "id": { "operator": "EQUAL", "value": "http://example.com" }, "issuer": { "operator": "EQUAL", "value": "http://example.com" }, "type": { "operator": "IN", "values": [ "string" ] }, "valid_from": { "operator": "BETWEEN", "left": "2019-08-24T14:15:22Z", "right": "2019-08-24T14:15:22Z" }, "valid_until": { "operator": "BETWEEN", "left": "2019-08-24T14:15:22Z", "right": "2019-08-24T14:15:22Z" } }, "deleted_at": { "operator": "BETWEEN", "left": "2019-08-24T14:15:22Z", "right": "2019-08-24T14:15:22Z" }, "etag": { "operator": "EQUAL", "value": "string" }, "id": { "operator": "EQUAL", "value": "a860a344-d7b2-406e-828e-8d442f23f344" }, "labels": [ { "operator": "EQUAL", "key": "string", "value": "string" } ], "modified_at": { "operator": "BETWEEN", "left": "2019-08-24T14:15:22Z", "right": "2019-08-24T14:15:22Z" }, "revision": { "operator": "EQUAL", "value": 1 } }, "linked_drafts": { "annotations": [ { "operator": "EQUAL", "key": "string", "value": "string" } ], "created_at": { "operator": "BETWEEN", "left": "2019-08-24T14:15:22Z", "right": "2019-08-24T14:15:22Z" }, "data": { "meta": { "subject": { "operator": "EQUAL", "value": "string" }, "valid_from": { "operator": "BETWEEN", "left": "2019-08-24T14:15:22Z", "right": "2019-08-24T14:15:22Z" }, "valid_until": { "operator": "BETWEEN", "left": "2019-08-24T14:15:22Z", "right": "2019-08-24T14:15:22Z" } }, "type": { "operator": "IN", "values": [ "string" ] } }, "deleted_at": { "operator": "BETWEEN", "left": "2019-08-24T14:15:22Z", "right": "2019-08-24T14:15:22Z" }, "etag": { "operator": "EQUAL", "value": "string" }, "id": { "operator": "EQUAL", "value": "a860a344-d7b2-406e-828e-8d442f23f344" }, "labels": [ { "operator": "EQUAL", "key": "string", "value": "string" } ], "modified_at": { "operator": "BETWEEN", "left": "2019-08-24T14:15:22Z", "right": "2019-08-24T14:15:22Z" }, "revision": { "operator": "EQUAL", "value": 1 } } } ], "sort": [ { "field": "DATA_TYPE", "order": "ASC" } ] }` ##### Response samples * 200 * 400 * 401 * 403 * 415 * 429 * 500 * default Content type application/json Copy Expand all Collapse all `{ "items": [ { "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "json_ld_vocabs": [ "http://example.com" ], "linked_credential_refs": [ { "blob_id": "http://example.com", "digest_multibase": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f" } ], "linked_draft_refs": [ { "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f" } ], "meta": { "subject": "string", "valid_from": "2019-08-24T14:15:22Z", "valid_until": "2019-08-24T14:15:22Z" }, "meta_schema": "http://example.com", "type": [ "string" ], "values": { "property1": { "kind": "STRING", "value": "string" }, "property2": { "kind": "STRING", "value": "string" } }, "vcdm_json_schemas": [ "http://example.com" ] }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 } ] }` #### [](#tag/drafts/operation/DraftDelete)Delete Draft. Delete Draft's resource. ###### Authorizations: *ApiKey* ###### path Parameters | | | | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | idrequired | string<uuid>The primary and unique identifier of the resource (inside tenant) according to [RFC 4122](https://www.rfc-editor.org/info/rfc4122). | ###### header Parameters | | | | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Idempotency-Key | string\[ 32 .. 256 ] characters\[a-zA-Z0-9-]{32,256}From [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **Idempotency-Key** is a free identifier created by the client to identify a request. It is used by the service to identify repeated request to ensure idempotent behavior by sending the same (or a similar) response without executing the request a second time.Clients should be careful as any subsequent requests with the same key may return the same response without further check. Thus, it is recommended to use a UUID version 4 (random) or any other random string with enough entropy to avoid collisions.Keys expire after 24 hours. Clients are responsible to stay within this limit, if they require idempotent behavior.See [API Guideline Rule #181](https://opensource.zalando.com/restful-api-guidelines/#230) for further details. | | If-Matchrequired | stringFrom [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **If-Match** header field is used to declare a list of identifiers that are required to match the current resource version identifier in at least one position as a pre-condition for executing the request on the server side. This behavior is used to validate and reject optimistic updates, by checking if the resource version a consumer has based his changes on is outdated on arrival of the change request to prevent lost updates.If the pre-condition fails the server will respond with status code **412** (Precondition Failed). See [RFC 9110 Section 13.1.1](https://tools.ietf.org/html/rfc9110#section-13.1.1) as well as \[API Guideline Rule #182]\[api-182] for further details.\[api-182]: . | ##### Responses **204** HTTP 204 - No content. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **404** The schema represents an HTTP "Not Found" status code. **405** The schema represents an HTTP "Method Not Allowed" status code. **412** The schema represents an HTTP "Precondition Failed" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. delete/drafts/{id} URL for header-protected customer communication. https://api.truvity.{zone}/drafts/{id} URL for cookie-protected customer communication. https://docs.truvity.com/api/drafts/{id} ##### Request samples * Go * Java * TypeScript Copy ##### Response samples * 400 * 401 * 403 * 404 * 405 * 412 * 429 * 500 * default Content type application/problem+json Example /bad-request/bad-request Copy Expand all Collapse all `{ "detail": "string", "errors": [ { "location": "string", "message": "string", "value": null } ], "instance": "http://example.com", "status": 100, "title": "string", "type": "/bad-request" }` #### [](#tag/drafts/operation/DraftLatest)Get the latest version of Draft. Get the latest version of Draft. ###### Authorizations: *ApiKey* ###### path Parameters | | | | ---------- | ------------------------------------------------------------------- | | idrequired | string<uuid>The ID of the resource. | ###### header Parameters | | | | ------------- | ----------------------------------------------------- | | If-None-Match | stringThe ETag of the latest version of the resource. | ##### Responses **200** Response with the latest Draft. **304** HTTP 304 - Not modified. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **404** The schema represents an HTTP "Not Found" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. get/drafts/{id} URL for header-protected customer communication. https://api.truvity.{zone}/drafts/{id} URL for cookie-protected customer communication. https://docs.truvity.com/api/drafts/{id} ##### Request samples * Go * Java * TypeScript Copy ##### Response samples * 200 * 400 * 401 * 403 * 404 * 429 * 500 * default Content type application/vnd.truvity.draft+json;version=1 Copy Expand all Collapse all `{ "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "json_ld_vocabs": [ "http://example.com" ], "linked_credential_refs": [ { "blob_id": "http://example.com", "digest_multibase": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f" } ], "linked_draft_refs": [ { "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f" } ], "meta": { "subject": "string", "valid_from": "2019-08-24T14:15:22Z", "valid_until": "2019-08-24T14:15:22Z" }, "meta_schema": "http://example.com", "type": [ "string" ], "values": { "property1": { "kind": "STRING", "value": "string" }, "property2": { "kind": "STRING", "value": "string" } }, "vcdm_json_schemas": [ "http://example.com" ] }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 }` #### [](#tag/drafts/operation/DraftUpdate)Update Draft. Update Draft's resource. ###### Authorizations: *ApiKey* ###### path Parameters | | | | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | idrequired | string<uuid>The primary and unique identifier of the resource (inside tenant) according to [RFC 4122](https://www.rfc-editor.org/info/rfc4122). | ###### header Parameters | | | | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Idempotency-Key | string\[ 32 .. 256 ] characters\[a-zA-Z0-9-]{32,256}From [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **Idempotency-Key** is a free identifier created by the client to identify a request. It is used by the service to identify repeated request to ensure idempotent behavior by sending the same (or a similar) response without executing the request a second time.Clients should be careful as any subsequent requests with the same key may return the same response without further check. Thus, it is recommended to use a UUID version 4 (random) or any other random string with enough entropy to avoid collisions.Keys expire after 24 hours. Clients are responsible to stay within this limit, if they require idempotent behavior.See [API Guideline Rule #181](https://opensource.zalando.com/restful-api-guidelines/#230) for further details. | | If-Matchrequired | stringFrom [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **If-Match** header field is used to declare a list of identifiers that are required to match the current resource version identifier in at least one position as a pre-condition for executing the request on the server side. This behavior is used to validate and reject optimistic updates, by checking if the resource version a consumer has based his changes on is outdated on arrival of the change request to prevent lost updates.If the pre-condition fails the server will respond with status code **412** (Precondition Failed). See [RFC 9110 Section 13.1.1](https://tools.ietf.org/html/rfc9110#section-13.1.1) as well as \[API Guideline Rule #182]\[api-182] for further details.\[api-182]: . | ###### Request Body schema: application/jsonrequired | | | | -------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------- | | datarequired | object (DraftUpdate)The data of the resource. | | meta object (DraftMeta) Metadata about the draft. values object (CredentialClaimValues) The values of the draft. | | ##### Responses **200** Response with the updated Draft. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **404** The schema represents an HTTP "Not Found" status code. **405** The schema represents an HTTP "Method Not Allowed" status code. **412** The schema represents an HTTP "Precondition Failed" status code. **415** The schema represents an HTTP "Unsupported Media Type" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. patch/drafts/{id} URL for header-protected customer communication. https://api.truvity.{zone}/drafts/{id} URL for cookie-protected customer communication. https://docs.truvity.com/api/drafts/{id} ##### Request samples * Payload * Go * Java * TypeScript Content type application/json Copy Expand all Collapse all `{ "data": { "meta": { "subject": "string", "valid_from": "2019-08-24T14:15:22Z", "valid_until": "2019-08-24T14:15:22Z" }, "values": { "property1": { "kind": "STRING", "value": "string" }, "property2": { "kind": "STRING", "value": "string" } } } }` ##### Response samples * 200 * 400 * 401 * 403 * 404 * 405 * 412 * 415 * 429 * 500 * default Content type application/vnd.truvity.draft+json;version=1 Copy Expand all Collapse all `{ "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "json_ld_vocabs": [ "http://example.com" ], "linked_credential_refs": [ { "blob_id": "http://example.com", "digest_multibase": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f" } ], "linked_draft_refs": [ { "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f" } ], "meta": { "subject": "string", "valid_from": "2019-08-24T14:15:22Z", "valid_until": "2019-08-24T14:15:22Z" }, "meta_schema": "http://example.com", "type": [ "string" ], "values": { "property1": { "kind": "STRING", "value": "string" }, "property2": { "kind": "STRING", "value": "string" } }, "vcdm_json_schemas": [ "http://example.com" ] }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 }` #### [](#tag/drafts/operation/DraftUpdateAnnotations)Update annotations. Update annotations of Draft's resource. ###### Authorizations: *ApiKey* ###### path Parameters | | | | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | idrequired | string<uuid>The primary and unique identifier of the resource (inside tenant) according to [RFC 4122](https://www.rfc-editor.org/info/rfc4122). | ###### header Parameters | | | | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Idempotency-Key | string\[ 32 .. 256 ] characters\[a-zA-Z0-9-]{32,256}From [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **Idempotency-Key** is a free identifier created by the client to identify a request. It is used by the service to identify repeated request to ensure idempotent behavior by sending the same (or a similar) response without executing the request a second time.Clients should be careful as any subsequent requests with the same key may return the same response without further check. Thus, it is recommended to use a UUID version 4 (random) or any other random string with enough entropy to avoid collisions.Keys expire after 24 hours. Clients are responsible to stay within this limit, if they require idempotent behavior.See [API Guideline Rule #181](https://opensource.zalando.com/restful-api-guidelines/#230) for further details. | | If-Matchrequired | stringFrom [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **If-Match** header field is used to declare a list of identifiers that are required to match the current resource version identifier in at least one position as a pre-condition for executing the request on the server side. This behavior is used to validate and reject optimistic updates, by checking if the resource version a consumer has based his changes on is outdated on arrival of the change request to prevent lost updates.If the pre-condition fails the server will respond with status code **412** (Precondition Failed). See [RFC 9110 Section 13.1.1](https://tools.ietf.org/html/rfc9110#section-13.1.1) as well as \[API Guideline Rule #182]\[api-182] for further details.\[api-182]: . | ###### Request Body schema: application/jsonrequired | | | | ----------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------- | | annotationsrequired | objectThe annotations of the resource. | | property name\* additional property string <= 128 characters ^\[^\n]{0,128}$ Value of the resource annotation. | | ##### Responses **200** Response with the updated Draft. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **404** The schema represents an HTTP "Not Found" status code. **405** The schema represents an HTTP "Method Not Allowed" status code. **412** The schema represents an HTTP "Precondition Failed" status code. **415** The schema represents an HTTP "Unsupported Media Type" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. patch/drafts/{id}/annotations URL for header-protected customer communication. https://api.truvity.{zone}/drafts/{id}/annotations URL for cookie-protected customer communication. https://docs.truvity.com/api/drafts/{id}/annotations ##### Request samples * Payload * Go * Java * TypeScript Content type application/json Copy Expand all Collapse all `{ "annotations": { "property1": "string", "property2": "string" } }` ##### Response samples * 200 * 400 * 401 * 403 * 404 * 405 * 412 * 415 * 429 * 500 * default Content type application/vnd.truvity.draft+json;version=1 Copy Expand all Collapse all `{ "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "json_ld_vocabs": [ "http://example.com" ], "linked_credential_refs": [ { "blob_id": "http://example.com", "digest_multibase": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f" } ], "linked_draft_refs": [ { "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f" } ], "meta": { "subject": "string", "valid_from": "2019-08-24T14:15:22Z", "valid_until": "2019-08-24T14:15:22Z" }, "meta_schema": "http://example.com", "type": [ "string" ], "values": { "property1": { "kind": "STRING", "value": "string" }, "property2": { "kind": "STRING", "value": "string" } }, "vcdm_json_schemas": [ "http://example.com" ] }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 }` #### [](#tag/drafts/operation/DraftLatestIssue)Issue a Verifiable Credential from Draft. This operation issues a Verifiable Credential from a Draft resource. Operational Lifecycle: 1. [Exporting](#tag/drafts/operation/DraftExport) Draft. 2. [Signing](#tag/keys/operation/CredentialSign) the exported Draft. 3. [Importing](#tag/credentials/operation/CredentialImport) the signed Credential. Cascade Issuance: If the Draft references other drafts the system automatically builds a dependency graph and issues all required drafts in the correct order. The correct order is a topological order of the dependency graph, where each draft is issued only after all its prerequisite drafts have been issued. Strict Mode: * The `strict_mode` option allows clients to control how prerequisite drafts are handled during cascade issuance. * Use `strict_mode` to enforce that only the explicitly specified drafts in `prerequisite_drafts` (with matching ETags) are accepted as prerequisites. * When disabled (default), the system will automatically discover and include all linked drafts as prerequisites, building the full dependency graph for cascade issuance. Performance Considerations: * The process may take longer than typical API calls due to: * Building and traversing the dependency graph for cascade issuance, which determines the correct issuance order for all linked drafts. * Fetching and resolving external resources required for generating cryptographic proofs, which may involve network requests. * Generating cryptographic proofs for each credential in the dependency graph. Concurrency and Consistency: * If the `If-Match` header is provided, strict version control is enforced. The operation will fail if the ETag does not match the current Draft version. * The endpoint is idempotent with respect to the Draft resource and ETag. Recovery: * If the issuance process fails at any stage, the operation can be safely retried. The endpoint is idempotent with respect to the Draft resource and ETag, so repeated calls will not result in duplicate credentials or inconsistent state. ###### Authorizations: *ApiKey* ###### path Parameters | | | | ---------- | ------------------------------------------------------------------- | | idrequired | string<uuid>The ID of the resource. | ###### header Parameters | | | | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | If-Match | stringFrom [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **If-Match** header field is used to declare a list of identifiers that are required to match the current resource version identifier in at least one position as a pre-condition for executing the request on the server side. This behavior is used to validate and reject optimistic updates, by checking if the resource version a consumer has based his changes on is outdated on arrival of the change request to prevent lost updates.If the pre-condition fails the server will respond with status code **412** (Precondition Failed). See [RFC 9110 Section 13.1.1](https://tools.ietf.org/html/rfc9110#section-13.1.1) as well as \[API Guideline Rule #182]\[api-182] for further details.\[api-182]: . | ###### Request Body schema: application/jsonrequired | | | | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | did\_method | stringDefault:"web"Enum: "key" "web"The DID method to use for the issuer DID. | | issuer | string<uri>The URI of the credential issuer. | | key\_idrequired | string<uuid>The ID of the key to sign the credential. | | prerequisite\_drafts | objectMap of draft URNs to their associated eTags for validation | | strict\_mode | booleanWhen enabled, the user must provide the full list of prerequisite draft IDs, and the system enforces this exact prerequisite graph. When disabled, the system automatically determines the dependency graph. | | valid\_from | string<date-time>The date and time the issued credential is valid from. | | valid\_until | string<date-time>The date and time the issued credential is valid until. | ##### Responses **200** The issued Verifiable Credential. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **404** The schema represents an HTTP "Not Found" status code. **405** The schema represents an HTTP "Method Not Allowed" status code. **412** The schema represents an HTTP "Precondition Failed" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **503** The schema represents an HTTP "Service Unavailable" status code. **default** The schema represents a default response. patch/drafts/{id}/issue URL for header-protected customer communication. https://api.truvity.{zone}/drafts/{id}/issue URL for cookie-protected customer communication. https://docs.truvity.com/api/drafts/{id}/issue ##### Request samples * Payload * Go * Java * TypeScript Content type application/json Copy Expand all Collapse all `{ "did_method": "key", "issuer": "http://example.com", "key_id": "1e779c8a-6786-4c89-b7c3-a6666f5fd6b5", "prerequisite_drafts": { "property1": "string", "property2": "string" }, "strict_mode": true, "valid_from": "2019-08-24T14:15:22Z", "valid_until": "2019-08-24T14:15:22Z" }` ##### Response samples * 200 * 400 * 401 * 403 * 404 * 405 * 412 * 429 * 500 * 503 * default Content type application/vnd.truvity.credential+json;version=1 Copy Expand all Collapse all `{ "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "data_model": { "flavor_name": "VC1_1", "expirationDate": "2019-08-24T14:15:22Z", "holder": "http://example.com", "id": "http://example.com", "issuanceDate": "2019-08-24T14:15:22Z", "issuer": "http://example.com", "proof": { "id": "string", "type": "string" }, "type": [ "string" ] }, "digest_multibase": "string", "holder": "http://example.com", "id": "http://example.com", "issuer": "http://example.com", "linked_credential_refs": [ { "blob_id": "http://example.com", "digest_multibase": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f" } ], "linked_file_refs": [ { "blob_id": "http://example.com", "digest_multibase": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f" } ], "type": [ "string" ], "valid_from": "2019-08-24T14:15:22Z", "valid_until": "2019-08-24T14:15:22Z" }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 }` #### [](#tag/drafts/operation/DraftUpdateLabels)Update labels. Update labels of Draft's resource. ###### Authorizations: *ApiKey* ###### path Parameters | | | | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | idrequired | string<uuid>The primary and unique identifier of the resource (inside tenant) according to [RFC 4122](https://www.rfc-editor.org/info/rfc4122). | ###### header Parameters | | | | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Idempotency-Key | string\[ 32 .. 256 ] characters\[a-zA-Z0-9-]{32,256}From [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **Idempotency-Key** is a free identifier created by the client to identify a request. It is used by the service to identify repeated request to ensure idempotent behavior by sending the same (or a similar) response without executing the request a second time.Clients should be careful as any subsequent requests with the same key may return the same response without further check. Thus, it is recommended to use a UUID version 4 (random) or any other random string with enough entropy to avoid collisions.Keys expire after 24 hours. Clients are responsible to stay within this limit, if they require idempotent behavior.See [API Guideline Rule #181](https://opensource.zalando.com/restful-api-guidelines/#230) for further details. | | If-Matchrequired | stringFrom [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **If-Match** header field is used to declare a list of identifiers that are required to match the current resource version identifier in at least one position as a pre-condition for executing the request on the server side. This behavior is used to validate and reject optimistic updates, by checking if the resource version a consumer has based his changes on is outdated on arrival of the change request to prevent lost updates.If the pre-condition fails the server will respond with status code **412** (Precondition Failed). See [RFC 9110 Section 13.1.1](https://tools.ietf.org/html/rfc9110#section-13.1.1) as well as \[API Guideline Rule #182]\[api-182] for further details.\[api-182]: . | ###### Request Body schema: application/jsonrequired | | | | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------- | | labelsrequired | objectThe labels of the resource. | | property name\* additional property string <= 63 characters ^(?:\[a-zA-Z0-9]\(?:\[a-zA-Z0-9\\.\\-\_]{0,61}\[a-zA...Show pattern Value of the resource label. | | ##### Responses **200** Response with the updated Draft. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **404** The schema represents an HTTP "Not Found" status code. **405** The schema represents an HTTP "Method Not Allowed" status code. **412** The schema represents an HTTP "Precondition Failed" status code. **415** The schema represents an HTTP "Unsupported Media Type" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. patch/drafts/{id}/labels URL for header-protected customer communication. https://api.truvity.{zone}/drafts/{id}/labels URL for cookie-protected customer communication. https://docs.truvity.com/api/drafts/{id}/labels ##### Request samples * Payload * Go * Java * TypeScript Content type application/json Copy Expand all Collapse all `{ "labels": { "property1": "string", "property2": "string" } }` ##### Response samples * 200 * 400 * 401 * 403 * 404 * 405 * 412 * 415 * 429 * 500 * default Content type application/vnd.truvity.draft+json;version=1 Copy Expand all Collapse all `{ "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "json_ld_vocabs": [ "http://example.com" ], "linked_credential_refs": [ { "blob_id": "http://example.com", "digest_multibase": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f" } ], "linked_draft_refs": [ { "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f" } ], "meta": { "subject": "string", "valid_from": "2019-08-24T14:15:22Z", "valid_until": "2019-08-24T14:15:22Z" }, "meta_schema": "http://example.com", "type": [ "string" ], "values": { "property1": { "kind": "STRING", "value": "string" }, "property2": { "kind": "STRING", "value": "string" } }, "vcdm_json_schemas": [ "http://example.com" ] }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 }` #### [](#tag/drafts/operation/DraftRestore)Restore Draft. Restore Draft's resource. ###### Authorizations: *ApiKey* ###### path Parameters | | | | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | idrequired | string<uuid>The primary and unique identifier of the resource (inside tenant) according to [RFC 4122](https://www.rfc-editor.org/info/rfc4122). | ###### header Parameters | | | | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Idempotency-Key | string\[ 32 .. 256 ] characters\[a-zA-Z0-9-]{32,256}From [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **Idempotency-Key** is a free identifier created by the client to identify a request. It is used by the service to identify repeated request to ensure idempotent behavior by sending the same (or a similar) response without executing the request a second time.Clients should be careful as any subsequent requests with the same key may return the same response without further check. Thus, it is recommended to use a UUID version 4 (random) or any other random string with enough entropy to avoid collisions.Keys expire after 24 hours. Clients are responsible to stay within this limit, if they require idempotent behavior.See [API Guideline Rule #181](https://opensource.zalando.com/restful-api-guidelines/#230) for further details. | | If-Matchrequired | stringFrom [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **If-Match** header field is used to declare a list of identifiers that are required to match the current resource version identifier in at least one position as a pre-condition for executing the request on the server side. This behavior is used to validate and reject optimistic updates, by checking if the resource version a consumer has based his changes on is outdated on arrival of the change request to prevent lost updates.If the pre-condition fails the server will respond with status code **412** (Precondition Failed). See [RFC 9110 Section 13.1.1](https://tools.ietf.org/html/rfc9110#section-13.1.1) as well as \[API Guideline Rule #182]\[api-182] for further details.\[api-182]: . | ##### Responses **200** Response with the restored Draft. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **404** The schema represents an HTTP "Not Found" status code. **405** The schema represents an HTTP "Method Not Allowed" status code. **412** The schema represents an HTTP "Precondition Failed" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. post/drafts/{id}/restore URL for header-protected customer communication. https://api.truvity.{zone}/drafts/{id}/restore URL for cookie-protected customer communication. https://docs.truvity.com/api/drafts/{id}/restore ##### Request samples * Go * Java * TypeScript Copy ##### Response samples * 200 * 400 * 401 * 403 * 404 * 405 * 412 * 429 * 500 * default Content type application/vnd.truvity.draft+json;version=1 Copy Expand all Collapse all `{ "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "json_ld_vocabs": [ "http://example.com" ], "linked_credential_refs": [ { "blob_id": "http://example.com", "digest_multibase": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f" } ], "linked_draft_refs": [ { "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f" } ], "meta": { "subject": "string", "valid_from": "2019-08-24T14:15:22Z", "valid_until": "2019-08-24T14:15:22Z" }, "meta_schema": "http://example.com", "type": [ "string" ], "values": { "property1": { "kind": "STRING", "value": "string" }, "property2": { "kind": "STRING", "value": "string" } }, "vcdm_json_schemas": [ "http://example.com" ] }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 }` #### [](#tag/drafts/operation/DraftHistory)Read Draft's history. History of the Draft's resources. ###### Authorizations: *ApiKey* ###### path Parameters | | | | ---------- | ------------------------------------------------------------------- | | idrequired | string<uuid>The ID of the resource. | ###### header Parameters | | | | ------------- | ----------------------------------------------------- | | If-None-Match | stringThe ETag of the latest version of the resource. | ##### Responses **200** Response with the history of Draft. **304** HTTP 304 - Not modified. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **404** The schema represents an HTTP "Not Found" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. get/drafts/{id}/revisions URL for header-protected customer communication. https://api.truvity.{zone}/drafts/{id}/revisions URL for cookie-protected customer communication. https://docs.truvity.com/api/drafts/{id}/revisions ##### Request samples * Go * Java * TypeScript Copy ##### Response samples * 200 * 400 * 401 * 403 * 404 * 429 * 500 * default Content type application/json Copy Expand all Collapse all `{ "items": [ { "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "json_ld_vocabs": [ "http://example.com" ], "linked_credential_refs": [ { "blob_id": "http://example.com", "digest_multibase": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f" } ], "linked_draft_refs": [ { "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f" } ], "meta": { "subject": "string", "valid_from": "2019-08-24T14:15:22Z", "valid_until": "2019-08-24T14:15:22Z" }, "meta_schema": "http://example.com", "type": [ "string" ], "values": { "property1": { "kind": "STRING", "value": "string" }, "property2": { "kind": "STRING", "value": "string" } }, "vcdm_json_schemas": [ "http://example.com" ] }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 } ] }` #### [](#tag/drafts/operation/DraftRevision)Read the specific version of the Draft. Read the specific version of the Draft's resource. ###### Authorizations: *ApiKey* ###### path Parameters | | | | ---------------- | ----------------------------------------------------------------------------------------------------------- | | idrequired | string<uuid>The ID of the resource. | | revisionrequired | integer<int32>\[ 1 .. 999999 ]The revision of the resource. | ###### header Parameters | | | | ------------- | ----------------------------------------------------- | | If-None-Match | stringThe ETag of the latest version of the resource. | ##### Responses **200** The requested revision of the Draft. **304** HTTP 304 - Not modified. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **404** The schema represents an HTTP "Not Found" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. get/drafts/{id}/revisions/{revision} URL for header-protected customer communication. https://api.truvity.{zone}/drafts/{id}/revisions/{revision} URL for cookie-protected customer communication. https://docs.truvity.com/api/drafts/{id}/revisions/{revision} ##### Request samples * Go * Java * TypeScript Copy ##### Response samples * 200 * 400 * 401 * 403 * 404 * 429 * 500 * default Content type application/json Copy Expand all Collapse all `{ "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "json_ld_vocabs": [ "http://example.com" ], "linked_credential_refs": [ { "blob_id": "http://example.com", "digest_multibase": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f" } ], "linked_draft_refs": [ { "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f" } ], "meta": { "subject": "string", "valid_from": "2019-08-24T14:15:22Z", "valid_until": "2019-08-24T14:15:22Z" }, "meta_schema": "http://example.com", "type": [ "string" ], "values": { "property1": { "kind": "STRING", "value": "string" }, "property2": { "kind": "STRING", "value": "string" } }, "vcdm_json_schemas": [ "http://example.com" ] }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 }` #### [](#tag/drafts/operation/DraftExport)Export Draft. Generate an unsigned Verifiable Credential in JSON-LD format from a Draft. ###### Authorizations: *ApiKey* ###### path Parameters | | | | ---------------- | ----------------------------------------------------------------------------------------------------------- | | idrequired | string<uuid>The ID of the resource. | | revisionrequired | integer<int32>\[ 1 .. 999999 ]The revision of the resource. | ###### Request Body schema: application/jsonrequired | | | | -------------- | -------------------------------------------------------------------------------------------------------- | | issuerrequired | string<uri>The URI of the credential issuer. | | valid\_from | string<date-time>The date and time the issued credential is valid from. | | valid\_until | string<date-time>The date and time the issued credential is valid until. | ##### Responses **200** The exported unsigned Verifiable Credential. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **404** The schema represents an HTTP "Not Found" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. post/drafts/{id}/revisions/{revision}/export URL for header-protected customer communication. https://api.truvity.{zone}/drafts/{id}/revisions/{revision}/export URL for cookie-protected customer communication. https://docs.truvity.com/api/drafts/{id}/revisions/{revision}/export ##### Request samples * Payload * Java * TypeScript Content type application/json Copy `{ "issuer": "http://example.com", "valid_from": "2019-08-24T14:15:22Z", "valid_until": "2019-08-24T14:15:22Z" }` ##### Response samples * 200 * 400 * 401 * 403 * 404 * 429 * 500 * default Content type application/vc+ld+json Copy `"string"` #### [](#tag/files)File The API to manage files. #### [](#tag/files/operation/FileCreate)Create File. Creates File's resource with **blob\_id**. To get **blob\_id** call [Upload](#tag/files/operation/FileUpload) first. ###### Authorizations: *ApiKey* ###### query Parameters | | | | ---------------- | ------------------------------------------------------------------------------------------------------- | | blob\_idrequired | string<uuid>The ID that returned on Upload operation in blob\_id field. | ###### header Parameters | | | | --------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Idempotency-Key | string\[ 32 .. 256 ] characters\[a-zA-Z0-9-]{32,256}From [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **Idempotency-Key** is a free identifier created by the client to identify a request. It is used by the service to identify repeated request to ensure idempotent behavior by sending the same (or a similar) response without executing the request a second time.Clients should be careful as any subsequent requests with the same key may return the same response without further check. Thus, it is recommended to use a UUID version 4 (random) or any other random string with enough entropy to avoid collisions.Keys expire after 24 hours. Clients are responsible to stay within this limit, if they require idempotent behavior.See [API Guideline Rule #181](https://opensource.zalando.com/restful-api-guidelines/#230) for further details. | ###### Request Body schema: application/jsonrequired | | | | ----------- | ----------------------------------------------------------- | | annotations | objectThe annotations of the resource. | | data | object (FileData)The data to create a file. | | labels | objectThe labels of the resource. | ##### Responses **201** Response with the newly created File. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **404** The schema represents an HTTP "Not Found" status code. **409** The schema represents an HTTP "Conflict" status code. **415** The schema represents an HTTP "Unsupported Media Type" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. post/files URL for header-protected customer communication. https://api.truvity.{zone}/files URL for cookie-protected customer communication. https://docs.truvity.com/api/files ##### Request samples * Payload * Go * Java * TypeScript Content type application/json Copy Expand all Collapse all `{ "annotations": { "property1": "string", "property2": "string" }, "data": { "filename": "string", "id": "http://example.com" }, "labels": { "property1": "string", "property2": "string" } }` ##### Response samples * 201 * 400 * 401 * 403 * 404 * 409 * 415 * 429 * 500 * default Content type application/vnd.truvity.file+json;version=1 Copy Expand all Collapse all `{ "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "content_type": "string", "digest_multibase": "string", "filename": "string", "filesize": 1, "id": "http://example.com" }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 }` #### [](#tag/files/operation/FileSearch)Search for Files. Search for Files with extended filters capabilities. ###### Authorizations: *ApiKey* ###### Request Body schema: application/jsonrequired | | | | ------ | ----------------------------------------------------------------------------------------------------------- | | filter | Array of objects (FileFilter)<= 4 itemsThe filter to apply to the search. | | sort | Array of objects (FileSort)<= 4 itemsThe sort order to apply to the search. | ##### Responses **200** The search results of File. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **415** The schema represents an HTTP "Unsupported Media Type" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. post/files/search URL for header-protected customer communication. https://api.truvity.{zone}/files/search URL for cookie-protected customer communication. https://docs.truvity.com/api/files/search ##### Request samples * Payload * Go * Java * TypeScript Content type application/json Copy Expand all Collapse all `{ "filter": [ { "annotations": [ { "operator": "EQUAL", "key": "string", "value": "string" } ], "created_at": { "operator": "BETWEEN", "left": "2019-08-24T14:15:22Z", "right": "2019-08-24T14:15:22Z" }, "data": { "content_type": { "operator": "EQUAL", "value": "string" }, "digest_multibase": { "operator": "EQUAL", "value": "string" }, "filename": { "operator": "EQUAL", "value": "string" }, "filesize": { "operator": "EQUAL", "value": 1 }, "id": { "operator": "EQUAL", "value": "http://example.com" } }, "deleted_at": { "operator": "BETWEEN", "left": "2019-08-24T14:15:22Z", "right": "2019-08-24T14:15:22Z" }, "etag": { "operator": "EQUAL", "value": "string" }, "id": { "operator": "EQUAL", "value": "a860a344-d7b2-406e-828e-8d442f23f344" }, "labels": [ { "operator": "EQUAL", "key": "string", "value": "string" } ], "modified_at": { "operator": "BETWEEN", "left": "2019-08-24T14:15:22Z", "right": "2019-08-24T14:15:22Z" }, "revision": { "operator": "EQUAL", "value": 1 } } ], "sort": [ { "field": "DATA_ID", "order": "ASC" } ] }` ##### Response samples * 200 * 400 * 401 * 403 * 415 * 429 * 500 * default Content type application/json Copy Expand all Collapse all `{ "items": [ { "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "content_type": "string", "digest_multibase": "string", "filename": "string", "filesize": 1, "id": "http://example.com" }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 } ] }` #### [](#tag/files/operation/FileUpload)Upload File's blob. Initiates a File blob upload, returning a pre-signed S3 URL. Response contains: * **blob\_id** (required for File creation) * **upload\_uri** (pre-signed URL for upload) * **timeout** (expiration in seconds). ###### Authorizations: *ApiKey* ###### header Parameters | | | | --------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Idempotency-Key | string\[ 32 .. 256 ] characters\[a-zA-Z0-9-]{32,256}From [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **Idempotency-Key** is a free identifier created by the client to identify a request. It is used by the service to identify repeated request to ensure idempotent behavior by sending the same (or a similar) response without executing the request a second time.Clients should be careful as any subsequent requests with the same key may return the same response without further check. Thus, it is recommended to use a UUID version 4 (random) or any other random string with enough entropy to avoid collisions.Keys expire after 24 hours. Clients are responsible to stay within this limit, if they require idempotent behavior.See [API Guideline Rule #181](https://opensource.zalando.com/restful-api-guidelines/#230) for further details. | ##### Responses **200** The result of uploading of File's resource. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. post/files/upload URL for header-protected customer communication. https://api.truvity.{zone}/files/upload URL for cookie-protected customer communication. https://docs.truvity.com/api/files/upload ##### Request samples * Go * Java * TypeScript Copy ##### Response samples * 200 * 400 * 401 * 403 * 429 * 500 * default Content type application/json Copy `{ "blob_id": "8249af2f-dd23-416e-b9c4-6cb13a792190", "timeout": 1, "upload_uri": "http://example.com" }` #### [](#tag/files/operation/FileDelete)Delete File. Delete File's resource. ###### Authorizations: *ApiKey* ###### path Parameters | | | | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | idrequired | string<uuid>The primary and unique identifier of the resource (inside tenant) according to [RFC 4122](https://www.rfc-editor.org/info/rfc4122). | ###### header Parameters | | | | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Idempotency-Key | string\[ 32 .. 256 ] characters\[a-zA-Z0-9-]{32,256}From [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **Idempotency-Key** is a free identifier created by the client to identify a request. It is used by the service to identify repeated request to ensure idempotent behavior by sending the same (or a similar) response without executing the request a second time.Clients should be careful as any subsequent requests with the same key may return the same response without further check. Thus, it is recommended to use a UUID version 4 (random) or any other random string with enough entropy to avoid collisions.Keys expire after 24 hours. Clients are responsible to stay within this limit, if they require idempotent behavior.See [API Guideline Rule #181](https://opensource.zalando.com/restful-api-guidelines/#230) for further details. | | If-Matchrequired | stringFrom [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **If-Match** header field is used to declare a list of identifiers that are required to match the current resource version identifier in at least one position as a pre-condition for executing the request on the server side. This behavior is used to validate and reject optimistic updates, by checking if the resource version a consumer has based his changes on is outdated on arrival of the change request to prevent lost updates.If the pre-condition fails the server will respond with status code **412** (Precondition Failed). See [RFC 9110 Section 13.1.1](https://tools.ietf.org/html/rfc9110#section-13.1.1) as well as \[API Guideline Rule #182]\[api-182] for further details.\[api-182]: . | ##### Responses **204** HTTP 204 - No content. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **404** The schema represents an HTTP "Not Found" status code. **405** The schema represents an HTTP "Method Not Allowed" status code. **412** The schema represents an HTTP "Precondition Failed" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. delete/files/{id} URL for header-protected customer communication. https://api.truvity.{zone}/files/{id} URL for cookie-protected customer communication. https://docs.truvity.com/api/files/{id} ##### Request samples * Go * Java * TypeScript Copy ##### Response samples * 400 * 401 * 403 * 404 * 405 * 412 * 429 * 500 * default Content type application/problem+json Example /bad-request/bad-request Copy Expand all Collapse all `{ "detail": "string", "errors": [ { "location": "string", "message": "string", "value": null } ], "instance": "http://example.com", "status": 100, "title": "string", "type": "/bad-request" }` #### [](#tag/files/operation/FileLatest)Get the latest version of File. Get the latest version of File. ###### Authorizations: *ApiKey* ###### path Parameters | | | | ---------- | ------------------------------------------------------------------- | | idrequired | string<uuid>The ID of the resource. | ###### header Parameters | | | | ------------- | ----------------------------------------------------- | | If-None-Match | stringThe ETag of the latest version of the resource. | ##### Responses **200** Response with the latest File. **304** HTTP 304 - Not modified. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **404** The schema represents an HTTP "Not Found" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. get/files/{id} URL for header-protected customer communication. https://api.truvity.{zone}/files/{id} URL for cookie-protected customer communication. https://docs.truvity.com/api/files/{id} ##### Request samples * Go * Java * TypeScript Copy ##### Response samples * 200 * 400 * 401 * 403 * 404 * 429 * 500 * default Content type application/vnd.truvity.file+json;version=1 Copy Expand all Collapse all `{ "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "content_type": "string", "digest_multibase": "string", "filename": "string", "filesize": 1, "id": "http://example.com" }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 }` #### [](#tag/files/operation/FileUpdateAnnotations)Update annotations. Update annotations of File's resource. ###### Authorizations: *ApiKey* ###### path Parameters | | | | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | idrequired | string<uuid>The primary and unique identifier of the resource (inside tenant) according to [RFC 4122](https://www.rfc-editor.org/info/rfc4122). | ###### header Parameters | | | | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Idempotency-Key | string\[ 32 .. 256 ] characters\[a-zA-Z0-9-]{32,256}From [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **Idempotency-Key** is a free identifier created by the client to identify a request. It is used by the service to identify repeated request to ensure idempotent behavior by sending the same (or a similar) response without executing the request a second time.Clients should be careful as any subsequent requests with the same key may return the same response without further check. Thus, it is recommended to use a UUID version 4 (random) or any other random string with enough entropy to avoid collisions.Keys expire after 24 hours. Clients are responsible to stay within this limit, if they require idempotent behavior.See [API Guideline Rule #181](https://opensource.zalando.com/restful-api-guidelines/#230) for further details. | | If-Matchrequired | stringFrom [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **If-Match** header field is used to declare a list of identifiers that are required to match the current resource version identifier in at least one position as a pre-condition for executing the request on the server side. This behavior is used to validate and reject optimistic updates, by checking if the resource version a consumer has based his changes on is outdated on arrival of the change request to prevent lost updates.If the pre-condition fails the server will respond with status code **412** (Precondition Failed). See [RFC 9110 Section 13.1.1](https://tools.ietf.org/html/rfc9110#section-13.1.1) as well as \[API Guideline Rule #182]\[api-182] for further details.\[api-182]: . | ###### Request Body schema: application/jsonrequired | | | | ----------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------- | | annotationsrequired | objectThe annotations of the resource. | | property name\* additional property string <= 128 characters ^\[^\n]{0,128}$ Value of the resource annotation. | | ##### Responses **200** Response with the updated File. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **404** The schema represents an HTTP "Not Found" status code. **405** The schema represents an HTTP "Method Not Allowed" status code. **412** The schema represents an HTTP "Precondition Failed" status code. **415** The schema represents an HTTP "Unsupported Media Type" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. patch/files/{id}/annotations URL for header-protected customer communication. https://api.truvity.{zone}/files/{id}/annotations URL for cookie-protected customer communication. https://docs.truvity.com/api/files/{id}/annotations ##### Request samples * Payload * Go * Java * TypeScript Content type application/json Copy Expand all Collapse all `{ "annotations": { "property1": "string", "property2": "string" } }` ##### Response samples * 200 * 400 * 401 * 403 * 404 * 405 * 412 * 415 * 429 * 500 * default Content type application/vnd.truvity.file+json;version=1 Copy Expand all Collapse all `{ "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "content_type": "string", "digest_multibase": "string", "filename": "string", "filesize": 1, "id": "http://example.com" }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 }` #### [](#tag/files/operation/FileUpdateLabels)Update labels. Update labels of File's resource. ###### Authorizations: *ApiKey* ###### path Parameters | | | | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | idrequired | string<uuid>The primary and unique identifier of the resource (inside tenant) according to [RFC 4122](https://www.rfc-editor.org/info/rfc4122). | ###### header Parameters | | | | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Idempotency-Key | string\[ 32 .. 256 ] characters\[a-zA-Z0-9-]{32,256}From [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **Idempotency-Key** is a free identifier created by the client to identify a request. It is used by the service to identify repeated request to ensure idempotent behavior by sending the same (or a similar) response without executing the request a second time.Clients should be careful as any subsequent requests with the same key may return the same response without further check. Thus, it is recommended to use a UUID version 4 (random) or any other random string with enough entropy to avoid collisions.Keys expire after 24 hours. Clients are responsible to stay within this limit, if they require idempotent behavior.See [API Guideline Rule #181](https://opensource.zalando.com/restful-api-guidelines/#230) for further details. | | If-Matchrequired | stringFrom [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **If-Match** header field is used to declare a list of identifiers that are required to match the current resource version identifier in at least one position as a pre-condition for executing the request on the server side. This behavior is used to validate and reject optimistic updates, by checking if the resource version a consumer has based his changes on is outdated on arrival of the change request to prevent lost updates.If the pre-condition fails the server will respond with status code **412** (Precondition Failed). See [RFC 9110 Section 13.1.1](https://tools.ietf.org/html/rfc9110#section-13.1.1) as well as \[API Guideline Rule #182]\[api-182] for further details.\[api-182]: . | ###### Request Body schema: application/jsonrequired | | | | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------- | | labelsrequired | objectThe labels of the resource. | | property name\* additional property string <= 63 characters ^(?:\[a-zA-Z0-9]\(?:\[a-zA-Z0-9\\.\\-\_]{0,61}\[a-zA...Show pattern Value of the resource label. | | ##### Responses **200** Response with the updated File. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **404** The schema represents an HTTP "Not Found" status code. **405** The schema represents an HTTP "Method Not Allowed" status code. **412** The schema represents an HTTP "Precondition Failed" status code. **415** The schema represents an HTTP "Unsupported Media Type" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. patch/files/{id}/labels URL for header-protected customer communication. https://api.truvity.{zone}/files/{id}/labels URL for cookie-protected customer communication. https://docs.truvity.com/api/files/{id}/labels ##### Request samples * Payload * Go * Java * TypeScript Content type application/json Copy Expand all Collapse all `{ "labels": { "property1": "string", "property2": "string" } }` ##### Response samples * 200 * 400 * 401 * 403 * 404 * 405 * 412 * 415 * 429 * 500 * default Content type application/vnd.truvity.file+json;version=1 Copy Expand all Collapse all `{ "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "content_type": "string", "digest_multibase": "string", "filename": "string", "filesize": 1, "id": "http://example.com" }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 }` #### [](#tag/files/operation/FileRestore)Restore File. Restore File's resource. ###### Authorizations: *ApiKey* ###### path Parameters | | | | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | idrequired | string<uuid>The primary and unique identifier of the resource (inside tenant) according to [RFC 4122](https://www.rfc-editor.org/info/rfc4122). | ###### header Parameters | | | | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Idempotency-Key | string\[ 32 .. 256 ] characters\[a-zA-Z0-9-]{32,256}From [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **Idempotency-Key** is a free identifier created by the client to identify a request. It is used by the service to identify repeated request to ensure idempotent behavior by sending the same (or a similar) response without executing the request a second time.Clients should be careful as any subsequent requests with the same key may return the same response without further check. Thus, it is recommended to use a UUID version 4 (random) or any other random string with enough entropy to avoid collisions.Keys expire after 24 hours. Clients are responsible to stay within this limit, if they require idempotent behavior.See [API Guideline Rule #181](https://opensource.zalando.com/restful-api-guidelines/#230) for further details. | | If-Matchrequired | stringFrom [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **If-Match** header field is used to declare a list of identifiers that are required to match the current resource version identifier in at least one position as a pre-condition for executing the request on the server side. This behavior is used to validate and reject optimistic updates, by checking if the resource version a consumer has based his changes on is outdated on arrival of the change request to prevent lost updates.If the pre-condition fails the server will respond with status code **412** (Precondition Failed). See [RFC 9110 Section 13.1.1](https://tools.ietf.org/html/rfc9110#section-13.1.1) as well as \[API Guideline Rule #182]\[api-182] for further details.\[api-182]: . | ##### Responses **200** Response with the restored File. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **404** The schema represents an HTTP "Not Found" status code. **405** The schema represents an HTTP "Method Not Allowed" status code. **412** The schema represents an HTTP "Precondition Failed" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. post/files/{id}/restore URL for header-protected customer communication. https://api.truvity.{zone}/files/{id}/restore URL for cookie-protected customer communication. https://docs.truvity.com/api/files/{id}/restore ##### Request samples * Go * Java * TypeScript Copy ##### Response samples * 200 * 400 * 401 * 403 * 404 * 405 * 412 * 429 * 500 * default Content type application/vnd.truvity.file+json;version=1 Copy Expand all Collapse all `{ "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "content_type": "string", "digest_multibase": "string", "filename": "string", "filesize": 1, "id": "http://example.com" }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 }` #### [](#tag/files/operation/FileHistory)Read File's history. History of the File's resources. ###### Authorizations: *ApiKey* ###### path Parameters | | | | ---------- | ------------------------------------------------------------------- | | idrequired | string<uuid>The ID of the resource. | ###### header Parameters | | | | ------------- | ----------------------------------------------------- | | If-None-Match | stringThe ETag of the latest version of the resource. | ##### Responses **200** Response with the history of File. **304** HTTP 304 - Not modified. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **404** The schema represents an HTTP "Not Found" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. get/files/{id}/revisions URL for header-protected customer communication. https://api.truvity.{zone}/files/{id}/revisions URL for cookie-protected customer communication. https://docs.truvity.com/api/files/{id}/revisions ##### Request samples * Go * Java * TypeScript Copy ##### Response samples * 200 * 400 * 401 * 403 * 404 * 429 * 500 * default Content type application/json Copy Expand all Collapse all `{ "items": [ { "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "content_type": "string", "digest_multibase": "string", "filename": "string", "filesize": 1, "id": "http://example.com" }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 } ] }` #### [](#tag/files/operation/FileRevision)Read the specific version of the File. Read the specific version of the File's resource. ###### Authorizations: *ApiKey* ###### path Parameters | | | | ---------------- | ----------------------------------------------------------------------------------------------------------- | | idrequired | string<uuid>The ID of the resource. | | revisionrequired | integer<int32>\[ 1 .. 999999 ]The revision of the resource. | ###### header Parameters | | | | ------------- | ----------------------------------------------------- | | If-None-Match | stringThe ETag of the latest version of the resource. | ##### Responses **200** The requested revision of the File. **304** HTTP 304 - Not modified. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **404** The schema represents an HTTP "Not Found" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. get/files/{id}/revisions/{revision} URL for header-protected customer communication. https://api.truvity.{zone}/files/{id}/revisions/{revision} URL for cookie-protected customer communication. https://docs.truvity.com/api/files/{id}/revisions/{revision} ##### Request samples * Go * Java * TypeScript Copy ##### Response samples * 200 * 400 * 401 * 403 * 404 * 429 * 500 * default Content type application/json Copy Expand all Collapse all `{ "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "content_type": "string", "digest_multibase": "string", "filename": "string", "filesize": 1, "id": "http://example.com" }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 }` #### [](#tag/files/operation/FileDownload)Download of File's blob. Download of File's blob. ###### Authorizations: *ApiKey* ###### path Parameters | | | | ---------------- | ----------------------------------------------------------------------------------------------------------- | | idrequired | string<uuid>The ID of the resource. | | revisionrequired | integer<int32>\[ 1 .. 999999 ]The revision of the resource. | ###### header Parameters | | | | ------------- | ----------------------------------------------------- | | If-None-Match | stringThe ETag of the latest version of the resource. | ##### Responses **200** The result of downloading of File's resource. **304** HTTP 304 - Not modified. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **404** The schema represents an HTTP "Not Found" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. get/files/{id}/revisions/{revision}/download URL for header-protected customer communication. https://api.truvity.{zone}/files/{id}/revisions/{revision}/download URL for cookie-protected customer communication. https://docs.truvity.com/api/files/{id}/revisions/{revision}/download ##### Request samples * Go * Java * TypeScript Copy ##### Response samples * 400 * 401 * 403 * 404 * 429 * 500 * default Content type application/problem+json Example /bad-request/bad-request Copy Expand all Collapse all `{ "detail": "string", "errors": [ { "location": "string", "message": "string", "value": null } ], "instance": "http://example.com", "status": 100, "title": "string", "type": "/bad-request" }` #### [](#tag/gdpr)GDPR The Truvity's Admin Panel API. #### [](#tag/gdpr/operation/SupportRequestCreate)Create a request to support. Create a request to support. ###### Authorizations: *ApiKey* ###### Request Body schema: application/jsonrequired | | | | --------------- | ----------------------------------------------------------------------------------------------------------- | | messagerequired | stringnon-emptyThe message of the support request. | | typerequired | stringEnum: "DATA\_DUMP" "DELETION" "OTHER" "RECTIFICATION"The type of the support request. | ##### Responses **204** HTTP 204 - No content. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. post/support-requests URL for header-protected customer communication. https://api.truvity.{zone}/support-requests URL for cookie-protected customer communication. https://docs.truvity.com/api/support-requests ##### Request samples * Payload * Go * Java * TypeScript Content type application/json Copy `{ "message": "string", "type": "DATA_DUMP" }` ##### Response samples * 400 * 401 * 403 * 500 * default Content type application/problem+json Example /bad-request/bad-request Copy Expand all Collapse all `{ "detail": "string", "errors": [ { "location": "string", "message": "string", "value": null } ], "instance": "http://example.com", "status": 100, "title": "string", "type": "/bad-request" }` #### [](#tag/keys)Key The API to manage cryptographical asymmetrical keys. #### [](#tag/keys/operation/KeyGenerate)Generate a new cryptographic key pair. Generate a new cryptographic key pair. ###### Authorizations: *ApiKey* ###### header Parameters | | | | --------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Idempotency-Key | string\[ 32 .. 256 ] characters\[a-zA-Z0-9-]{32,256}From [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **Idempotency-Key** is a free identifier created by the client to identify a request. It is used by the service to identify repeated request to ensure idempotent behavior by sending the same (or a similar) response without executing the request a second time.Clients should be careful as any subsequent requests with the same key may return the same response without further check. Thus, it is recommended to use a UUID version 4 (random) or any other random string with enough entropy to avoid collisions.Keys expire after 24 hours. Clients are responsible to stay within this limit, if they require idempotent behavior.See [API Guideline Rule #181](https://opensource.zalando.com/restful-api-guidelines/#230) for further details. | ###### Request Body schema: application/jsonrequired | | | | ------------ | --------------------------------------------------------------- | | annotations | objectThe annotations of the resource. | | datarequired | object (KeyGenerate)The Key generation request. | | labels | objectThe labels of the resource. | ##### Responses **201** The generated Key with requested type. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **415** The schema represents an HTTP "Unsupported Media Type" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. post/keys/generate URL for header-protected customer communication. https://api.truvity.{zone}/keys/generate URL for cookie-protected customer communication. https://docs.truvity.com/api/keys/generate ##### Request samples * Payload * Go * Java * TypeScript Content type application/json Copy Expand all Collapse all `{ "annotations": { "property1": "string", "property2": "string" }, "data": { "type": "ED25519" }, "labels": { "property1": "string", "property2": "string" } }` ##### Response samples * 201 * 400 * 401 * 403 * 415 * 429 * 500 * default Content type application/vnd.truvity.key+json;version=1 Copy Expand all Collapse all `{ "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "publicKeyBase58": "string", "publicKeyJwk": "crv: P-384\nkty: EC\nx: m2Gee3mEeKWmMuHiSUqeCrsqlWAHGG-Y8k4FoEhJjVl9zDpjGo3J0LrQAcL1Ns7K\n\"y\": 3FGUwlmVJznpuoBMWU68W1YIxGFx8usj23cR0miRGwGpZx3tQhx8CyG8JgX6BEnm\n\t\t", "publicKeyMultibase": "string", "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEm2Gee3mEeKWmMuHiSUqeCrsqlWAHGG+Y\n8k4FoEhJjVl9zDpjGo3J0LrQAcL1Ns7K3FGUwlmVJznpuoBMWU68W1YIxGFx8usj\n23cR0miRGwGpZx3tQhx8CyG8JgX6BEnm\n-----END PUBLIC KEY-----", "type": "ED25519" }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 }` #### [](#tag/keys/operation/KeyImport)Import a cryptographic key pair You could use KeyGenerate, if you want to rely to generated by Truvity key-pairs for CredentialIssue and PresentationIssue. Remember, that you do not have any option to get private key by Truvity API, you could only use it If you prefer to keep private key, then you need to generate it manually. To use manually generated key CredentialIssue and PresentationIssue you need to import it. To generate key-pair you have two options 1. OpenSSL - [OpenSSL commands](https://www.openssl.org/docs/man1.1.1/man1/index.html) 2. JWX tool - How to install JWX 1. Download & Install Golang - 2. Clone & Build & Install [github.com/lestrrat-go/jwx](https://github.com/lestrrat-go/jwx) ``` git clone https://github.com/lestrrat-go/jwx cd jwx/cmd/jwx go install -tags=jwx_es256k,jwx_secp256k1_pem . ``` 3. Verify that you correctly install everything ``` ➜ jwx --help NAME: jwx - Tools for various JWE/JWK/JWS/JWT operations USAGE: jwx [global options] command [command options] [arguments...] COMMANDS: jwa List available algorithms and types jwe Work with JWE messages jwk Work with JWK and JWK sets jws Work with JWS messages help, h Shows a list of commands or help for one command GLOBAL OPTIONS: --help, -h show help ``` How generate private key by `jwx` (output format JWK) ``` # ED25519 jwx jwx generate --type OKP --curve Ed25519 # P256 jwx jwx generate --type EC --curve P-256 # P384 jwx jwx generate --type EC --curve P-384 ``` How to generate public key from private key by `jwx` (input format - JWK, output format - JWK) ``` jwx jwk format -I json -O json - <(pathfile with private key in JWK format) ``` How to generate private key by OpenSSL (output format PEM - PKCS#8) ``` # ED25519 openssl genpkey -algorithm ed25519 | openssl pkcs8 -nocrypt -topk8 # P256 openssl ecparam -name prime256v1 -noout -genkey | openssl pkcs8 -nocrypt -topk8 # P384 openssl ecparam -name secp384r1 -noout -genkey | openssl pkcs8 -nocrypt -topk8 ``` How to transform existing private key to PKCS8 format by OpenSSL (input format PEM, output format - PEM PCKS#8) ``` openssl pkcs8 -nocrypt -topk8 <(pathfile with private key in PEM format) ``` How to transform private key to public key by OpenSSL (input format PEM, output format - PEM PKIX) ``` openssl pkey -pubout <(pathfile with private key in PKCS8 format) ``` Useful third-party documentation: * [openssl-genrsa - generate an RSA private key](https://www.openssl.org/docs/manmaster/man1/openssl-genpkey.html). * [openssl-ec, ec - EC key processing](https://www.openssl.org/docs/man1.0.2/man1/ec.html) * [openssl-genrsa - generate an RSA private key](https://www.openssl.org/docs/man3.0/man1/openssl-genrsa.html) * [openssl-pkcs8 - PKCS#8 format private key conversion command](https://www.openssl.org/docs/manmaster/man1/openssl-pkcs8.html) * [JWX - github.com/lestrrat-go/jwx](https://github.com/lestrrat-go/jwx/blob/main/cmd/jwx/README.md) * [FIPS 186-4](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf). * [SEC2](https://www.secg.org/sec2-v2.pdf). * [AWS KMS - Asymmetric key specs](https://docs.aws.amazon.com/kms/latest/developerguide/asymmetric-key-specs.html) . ###### Authorizations: *ApiKey* ###### header Parameters | | | | --------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Idempotency-Key | string\[ 32 .. 256 ] characters\[a-zA-Z0-9-]{32,256}From [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **Idempotency-Key** is a free identifier created by the client to identify a request. It is used by the service to identify repeated request to ensure idempotent behavior by sending the same (or a similar) response without executing the request a second time.Clients should be careful as any subsequent requests with the same key may return the same response without further check. Thus, it is recommended to use a UUID version 4 (random) or any other random string with enough entropy to avoid collisions.Keys expire after 24 hours. Clients are responsible to stay within this limit, if they require idempotent behavior.See [API Guideline Rule #181](https://opensource.zalando.com/restful-api-guidelines/#230) for further details. | ###### Request Body schema: application/jsonrequired | | | | ------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | annotations | objectThe annotations of the resource. | | datarequired | KeySecretEC (string) or KeySecretPKCS8 (string) or KeySecretJWK (string)Import secret key. Supported formats:- PEM-encoded PKCS#8
- PEM-encoded EC
- JWK format . | | labels | objectThe labels of the resource. | ##### Responses **201** The successfully imported Key. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **415** The schema represents an HTTP "Unsupported Media Type" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. post/keys/import URL for header-protected customer communication. https://api.truvity.{zone}/keys/import URL for cookie-protected customer communication. https://docs.truvity.com/api/keys/import ##### Request samples * Payload * Go * Java * TypeScript Content type application/json Copy Expand all Collapse all `{ "annotations": { "property1": "string", "property2": "string" }, "data": "-----BEGIN EC PRIVATE KEY-----\nMIGkAgEBBDBFFFnxnAX/kHeXe3g3mHEBTrGxD6WRyeH00FdzenriKZM5r1//lFA/\nmbfRZzsc+WOgBwYFK4EEACKhZANiAASbYZ57eYR4paYy4eJJSp4KuyqVYAcYb5jy\nTgWgSEmNWX3MOmMajcnQutABwvU2zsrcUZTCWZUnOem6gExZTrxbVgjEYXHy6yPb\ndxHSaJEbAalnHe1CHHwLIbwmBfoESeY=\n-----END EC PRIVATE KEY-----", "labels": { "property1": "string", "property2": "string" } }` ##### Response samples * 201 * 400 * 401 * 403 * 415 * 429 * 500 * default Content type application/vnd.truvity.key+json;version=1 Copy Expand all Collapse all `{ "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "publicKeyBase58": "string", "publicKeyJwk": "crv: P-384\nkty: EC\nx: m2Gee3mEeKWmMuHiSUqeCrsqlWAHGG-Y8k4FoEhJjVl9zDpjGo3J0LrQAcL1Ns7K\n\"y\": 3FGUwlmVJznpuoBMWU68W1YIxGFx8usj23cR0miRGwGpZx3tQhx8CyG8JgX6BEnm\n\t\t", "publicKeyMultibase": "string", "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEm2Gee3mEeKWmMuHiSUqeCrsqlWAHGG+Y\n8k4FoEhJjVl9zDpjGo3J0LrQAcL1Ns7K3FGUwlmVJznpuoBMWU68W1YIxGFx8usj\n23cR0miRGwGpZx3tQhx8CyG8JgX6BEnm\n-----END PUBLIC KEY-----", "type": "ED25519" }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 }` #### [](#tag/keys/operation/KeySearch)Search for Keys. Search for Keys with extended filters capabilities. ###### Authorizations: *ApiKey* ###### Request Body schema: application/jsonrequired | | | | ------ | ---------------------------------------------------------------------------------------------------------- | | filter | Array of objects (KeyFilter)<= 4 itemsThe filter to apply to the search. | | sort | Array of objects (KeySort)<= 4 itemsThe sort order to apply to the search. | ##### Responses **200** The search results of Key. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **415** The schema represents an HTTP "Unsupported Media Type" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. post/keys/search URL for header-protected customer communication. https://api.truvity.{zone}/keys/search URL for cookie-protected customer communication. https://docs.truvity.com/api/keys/search ##### Request samples * Payload * Go * Java * TypeScript Content type application/json Copy Expand all Collapse all `{ "filter": [ { "annotations": [ { "operator": "EQUAL", "key": "string", "value": "string" } ], "created_at": { "operator": "BETWEEN", "left": "2019-08-24T14:15:22Z", "right": "2019-08-24T14:15:22Z" }, "data": { "publicKeyBase58": { "operator": "EQUAL", "value": "string" }, "publicKeyMultibase": { "operator": "EQUAL", "value": "string" }, "publicKeyPem": { "operator": "EQUAL", "value": "-----BEGIN PUBLIC KEY-----\nMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEm2Gee3mEeKWmMuHiSUqeCrsqlWAHGG+Y\n8k4FoEhJjVl9zDpjGo3J0LrQAcL1Ns7K3FGUwlmVJznpuoBMWU68W1YIxGFx8usj\n23cR0miRGwGpZx3tQhx8CyG8JgX6BEnm\n-----END PUBLIC KEY-----" }, "type": { "operator": "EQUAL", "value": "ED25519" } }, "deleted_at": { "operator": "BETWEEN", "left": "2019-08-24T14:15:22Z", "right": "2019-08-24T14:15:22Z" }, "etag": { "operator": "EQUAL", "value": "string" }, "id": { "operator": "EQUAL", "value": "a860a344-d7b2-406e-828e-8d442f23f344" }, "labels": [ { "operator": "EQUAL", "key": "string", "value": "string" } ], "modified_at": { "operator": "BETWEEN", "left": "2019-08-24T14:15:22Z", "right": "2019-08-24T14:15:22Z" }, "revision": { "operator": "EQUAL", "value": 1 } } ], "sort": [ { "field": "DATA_TYPE", "order": "ASC" } ] }` ##### Response samples * 200 * 400 * 401 * 403 * 415 * 429 * 500 * default Content type application/json Copy Expand all Collapse all `{ "items": [ { "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "publicKeyBase58": "string", "publicKeyJwk": "crv: P-384\nkty: EC\nx: m2Gee3mEeKWmMuHiSUqeCrsqlWAHGG-Y8k4FoEhJjVl9zDpjGo3J0LrQAcL1Ns7K\n\"y\": 3FGUwlmVJznpuoBMWU68W1YIxGFx8usj23cR0miRGwGpZx3tQhx8CyG8JgX6BEnm\n\t\t", "publicKeyMultibase": "string", "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEm2Gee3mEeKWmMuHiSUqeCrsqlWAHGG+Y\n8k4FoEhJjVl9zDpjGo3J0LrQAcL1Ns7K3FGUwlmVJznpuoBMWU68W1YIxGFx8usj\n23cR0miRGwGpZx3tQhx8CyG8JgX6BEnm\n-----END PUBLIC KEY-----", "type": "ED25519" }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 } ] }` #### [](#tag/keys/operation/KeyDelete)Delete Key. Delete Key's resource. ###### Authorizations: *ApiKey* ###### path Parameters | | | | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | idrequired | string<uuid>The primary and unique identifier of the resource (inside tenant) according to [RFC 4122](https://www.rfc-editor.org/info/rfc4122). | ###### header Parameters | | | | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Idempotency-Key | string\[ 32 .. 256 ] characters\[a-zA-Z0-9-]{32,256}From [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **Idempotency-Key** is a free identifier created by the client to identify a request. It is used by the service to identify repeated request to ensure idempotent behavior by sending the same (or a similar) response without executing the request a second time.Clients should be careful as any subsequent requests with the same key may return the same response without further check. Thus, it is recommended to use a UUID version 4 (random) or any other random string with enough entropy to avoid collisions.Keys expire after 24 hours. Clients are responsible to stay within this limit, if they require idempotent behavior.See [API Guideline Rule #181](https://opensource.zalando.com/restful-api-guidelines/#230) for further details. | | If-Matchrequired | stringFrom [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **If-Match** header field is used to declare a list of identifiers that are required to match the current resource version identifier in at least one position as a pre-condition for executing the request on the server side. This behavior is used to validate and reject optimistic updates, by checking if the resource version a consumer has based his changes on is outdated on arrival of the change request to prevent lost updates.If the pre-condition fails the server will respond with status code **412** (Precondition Failed). See [RFC 9110 Section 13.1.1](https://tools.ietf.org/html/rfc9110#section-13.1.1) as well as \[API Guideline Rule #182]\[api-182] for further details.\[api-182]: . | ##### Responses **204** HTTP 204 - No content. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **404** The schema represents an HTTP "Not Found" status code. **405** The schema represents an HTTP "Method Not Allowed" status code. **412** The schema represents an HTTP "Precondition Failed" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. delete/keys/{id} URL for header-protected customer communication. https://api.truvity.{zone}/keys/{id} URL for cookie-protected customer communication. https://docs.truvity.com/api/keys/{id} ##### Request samples * Go * Java * TypeScript Copy ##### Response samples * 400 * 401 * 403 * 404 * 405 * 412 * 429 * 500 * default Content type application/problem+json Example /bad-request/bad-request Copy Expand all Collapse all `{ "detail": "string", "errors": [ { "location": "string", "message": "string", "value": null } ], "instance": "http://example.com", "status": 100, "title": "string", "type": "/bad-request" }` #### [](#tag/keys/operation/KeyLatest)Get the latest version of Key. Get the latest version of Key. ###### Authorizations: *ApiKey* ###### path Parameters | | | | ---------- | ------------------------------------------------------------------- | | idrequired | string<uuid>The ID of the resource. | ###### header Parameters | | | | ------------- | ----------------------------------------------------- | | If-None-Match | stringThe ETag of the latest version of the resource. | ##### Responses **200** Response with the latest Key. **304** HTTP 304 - Not modified. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **404** The schema represents an HTTP "Not Found" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. get/keys/{id} URL for header-protected customer communication. https://api.truvity.{zone}/keys/{id} URL for cookie-protected customer communication. https://docs.truvity.com/api/keys/{id} ##### Request samples * Go * Java * TypeScript Copy ##### Response samples * 200 * 400 * 401 * 403 * 404 * 429 * 500 * default Content type application/vnd.truvity.key+json;version=1 Copy Expand all Collapse all `{ "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "publicKeyBase58": "string", "publicKeyJwk": "crv: P-384\nkty: EC\nx: m2Gee3mEeKWmMuHiSUqeCrsqlWAHGG-Y8k4FoEhJjVl9zDpjGo3J0LrQAcL1Ns7K\n\"y\": 3FGUwlmVJznpuoBMWU68W1YIxGFx8usj23cR0miRGwGpZx3tQhx8CyG8JgX6BEnm\n\t\t", "publicKeyMultibase": "string", "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEm2Gee3mEeKWmMuHiSUqeCrsqlWAHGG+Y\n8k4FoEhJjVl9zDpjGo3J0LrQAcL1Ns7K3FGUwlmVJznpuoBMWU68W1YIxGFx8usj\n23cR0miRGwGpZx3tQhx8CyG8JgX6BEnm\n-----END PUBLIC KEY-----", "type": "ED25519" }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 }` #### [](#tag/keys/operation/KeyUpdateAnnotations)Update annotations. Update annotations of Key's resource. ###### Authorizations: *ApiKey* ###### path Parameters | | | | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | idrequired | string<uuid>The primary and unique identifier of the resource (inside tenant) according to [RFC 4122](https://www.rfc-editor.org/info/rfc4122). | ###### header Parameters | | | | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Idempotency-Key | string\[ 32 .. 256 ] characters\[a-zA-Z0-9-]{32,256}From [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **Idempotency-Key** is a free identifier created by the client to identify a request. It is used by the service to identify repeated request to ensure idempotent behavior by sending the same (or a similar) response without executing the request a second time.Clients should be careful as any subsequent requests with the same key may return the same response without further check. Thus, it is recommended to use a UUID version 4 (random) or any other random string with enough entropy to avoid collisions.Keys expire after 24 hours. Clients are responsible to stay within this limit, if they require idempotent behavior.See [API Guideline Rule #181](https://opensource.zalando.com/restful-api-guidelines/#230) for further details. | | If-Matchrequired | stringFrom [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **If-Match** header field is used to declare a list of identifiers that are required to match the current resource version identifier in at least one position as a pre-condition for executing the request on the server side. This behavior is used to validate and reject optimistic updates, by checking if the resource version a consumer has based his changes on is outdated on arrival of the change request to prevent lost updates.If the pre-condition fails the server will respond with status code **412** (Precondition Failed). See [RFC 9110 Section 13.1.1](https://tools.ietf.org/html/rfc9110#section-13.1.1) as well as \[API Guideline Rule #182]\[api-182] for further details.\[api-182]: . | ###### Request Body schema: application/jsonrequired | | | | ----------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------- | | annotationsrequired | objectThe annotations of the resource. | | property name\* additional property string <= 128 characters ^\[^\n]{0,128}$ Value of the resource annotation. | | ##### Responses **200** Response with the updated Key. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **404** The schema represents an HTTP "Not Found" status code. **405** The schema represents an HTTP "Method Not Allowed" status code. **412** The schema represents an HTTP "Precondition Failed" status code. **415** The schema represents an HTTP "Unsupported Media Type" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. patch/keys/{id}/annotations URL for header-protected customer communication. https://api.truvity.{zone}/keys/{id}/annotations URL for cookie-protected customer communication. https://docs.truvity.com/api/keys/{id}/annotations ##### Request samples * Payload * Go * Java * TypeScript Content type application/json Copy Expand all Collapse all `{ "annotations": { "property1": "string", "property2": "string" } }` ##### Response samples * 200 * 400 * 401 * 403 * 404 * 405 * 412 * 415 * 429 * 500 * default Content type application/vnd.truvity.key+json;version=1 Copy Expand all Collapse all `{ "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "publicKeyBase58": "string", "publicKeyJwk": "crv: P-384\nkty: EC\nx: m2Gee3mEeKWmMuHiSUqeCrsqlWAHGG-Y8k4FoEhJjVl9zDpjGo3J0LrQAcL1Ns7K\n\"y\": 3FGUwlmVJznpuoBMWU68W1YIxGFx8usj23cR0miRGwGpZx3tQhx8CyG8JgX6BEnm\n\t\t", "publicKeyMultibase": "string", "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEm2Gee3mEeKWmMuHiSUqeCrsqlWAHGG+Y\n8k4FoEhJjVl9zDpjGo3J0LrQAcL1Ns7K3FGUwlmVJznpuoBMWU68W1YIxGFx8usj\n23cR0miRGwGpZx3tQhx8CyG8JgX6BEnm\n-----END PUBLIC KEY-----", "type": "ED25519" }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 }` #### [](#tag/keys/operation/CredentialSign)Sign an unsigned Credential. Sign a JSON-LD representation of an unsigned Credential. ###### Authorizations: *ApiKey* ###### path Parameters | | | | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | idrequired | string<uuid>The primary and unique identifier of the resource (inside tenant) according to [RFC 4122](https://www.rfc-editor.org/info/rfc4122). | ###### query Parameters | | | | ----------- | ---------------------------------------------------------------------------------------------------------------- | | did\_method | stringDefault:"web"Enum: "key" "web"All supported DID methods. Default is "web". | ###### Request Body schema: application/jsonrequired string < binary \> < base64 \> < application/octet-stream \> The unsigned credential to sign. ##### Responses **200** The signed Verifiable Credential. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **404** The schema represents an HTTP "Not Found" status code. **405** The schema represents an HTTP "Method Not Allowed" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. post/keys/{id}/credentials/sign URL for header-protected customer communication. https://api.truvity.{zone}/keys/{id}/credentials/sign URL for cookie-protected customer communication. https://docs.truvity.com/api/keys/{id}/credentials/sign ##### Request samples * Payload * Go * Java * TypeScript Content type application/json Copy `"string"` ##### Response samples * 200 * 400 * 401 * 403 * 404 * 405 * 429 * 500 * default Content type application/vc+ld+json Copy `"string"` #### [](#tag/keys/operation/DIDCommMessageSign)Sign DIDComm Message Plaintext. Sign DIDComm Message Plaintext. ###### Authorizations: *ApiKey* ###### path Parameters | | | | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | idrequired | string<uuid>The primary and unique identifier of the resource (inside tenant) according to [RFC 4122](https://www.rfc-editor.org/info/rfc4122). | ###### query Parameters | | | | ----------- | ---------------------------------------------------------------------------------------------------------------- | | did\_method | stringDefault:"web"Enum: "key" "web"All supported DID methods. Default is "web". | ###### Request Body schema: application/jsonrequired string < binary \> < base64 \> < application/octet-stream \> The DIDCOMMMessage to sign. ##### Responses **200** The signed DIDCOMM message. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **404** The schema represents an HTTP "Not Found" status code. **405** The schema represents an HTTP "Method Not Allowed" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. post/keys/{id}/didcomm-messages/sign URL for header-protected customer communication. https://api.truvity.{zone}/keys/{id}/didcomm-messages/sign URL for cookie-protected customer communication. https://docs.truvity.com/api/keys/{id}/didcomm-messages/sign ##### Request samples * Payload * Go * Java * TypeScript Content type application/json Copy `"string"` ##### Response samples * 200 * 400 * 401 * 403 * 404 * 405 * 429 * 500 * default Content type application/didcomm-signed+json Copy `"string"` #### [](#tag/keys/operation/KeyUpdateLabels)Update labels. Update labels of Key's resource. ###### Authorizations: *ApiKey* ###### path Parameters | | | | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | idrequired | string<uuid>The primary and unique identifier of the resource (inside tenant) according to [RFC 4122](https://www.rfc-editor.org/info/rfc4122). | ###### header Parameters | | | | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Idempotency-Key | string\[ 32 .. 256 ] characters\[a-zA-Z0-9-]{32,256}From [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **Idempotency-Key** is a free identifier created by the client to identify a request. It is used by the service to identify repeated request to ensure idempotent behavior by sending the same (or a similar) response without executing the request a second time.Clients should be careful as any subsequent requests with the same key may return the same response without further check. Thus, it is recommended to use a UUID version 4 (random) or any other random string with enough entropy to avoid collisions.Keys expire after 24 hours. Clients are responsible to stay within this limit, if they require idempotent behavior.See [API Guideline Rule #181](https://opensource.zalando.com/restful-api-guidelines/#230) for further details. | | If-Matchrequired | stringFrom [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **If-Match** header field is used to declare a list of identifiers that are required to match the current resource version identifier in at least one position as a pre-condition for executing the request on the server side. This behavior is used to validate and reject optimistic updates, by checking if the resource version a consumer has based his changes on is outdated on arrival of the change request to prevent lost updates.If the pre-condition fails the server will respond with status code **412** (Precondition Failed). See [RFC 9110 Section 13.1.1](https://tools.ietf.org/html/rfc9110#section-13.1.1) as well as \[API Guideline Rule #182]\[api-182] for further details.\[api-182]: . | ###### Request Body schema: application/jsonrequired | | | | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------- | | labelsrequired | objectThe labels of the resource. | | property name\* additional property string <= 63 characters ^(?:\[a-zA-Z0-9]\(?:\[a-zA-Z0-9\\.\\-\_]{0,61}\[a-zA...Show pattern Value of the resource label. | | ##### Responses **200** Response with the updated Key. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **404** The schema represents an HTTP "Not Found" status code. **405** The schema represents an HTTP "Method Not Allowed" status code. **412** The schema represents an HTTP "Precondition Failed" status code. **415** The schema represents an HTTP "Unsupported Media Type" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. patch/keys/{id}/labels URL for header-protected customer communication. https://api.truvity.{zone}/keys/{id}/labels URL for cookie-protected customer communication. https://docs.truvity.com/api/keys/{id}/labels ##### Request samples * Payload * Go * Java * TypeScript Content type application/json Copy Expand all Collapse all `{ "labels": { "property1": "string", "property2": "string" } }` ##### Response samples * 200 * 400 * 401 * 403 * 404 * 405 * 412 * 415 * 429 * 500 * default Content type application/vnd.truvity.key+json;version=1 Copy Expand all Collapse all `{ "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "publicKeyBase58": "string", "publicKeyJwk": "crv: P-384\nkty: EC\nx: m2Gee3mEeKWmMuHiSUqeCrsqlWAHGG-Y8k4FoEhJjVl9zDpjGo3J0LrQAcL1Ns7K\n\"y\": 3FGUwlmVJznpuoBMWU68W1YIxGFx8usj23cR0miRGwGpZx3tQhx8CyG8JgX6BEnm\n\t\t", "publicKeyMultibase": "string", "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEm2Gee3mEeKWmMuHiSUqeCrsqlWAHGG+Y\n8k4FoEhJjVl9zDpjGo3J0LrQAcL1Ns7K3FGUwlmVJznpuoBMWU68W1YIxGFx8usj\n23cR0miRGwGpZx3tQhx8CyG8JgX6BEnm\n-----END PUBLIC KEY-----", "type": "ED25519" }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 }` #### [](#tag/keys/operation/PresentationSign)Sign an unsigned Presentation. Sign a JSON-LD representation of an unsigned Presentation. ###### Authorizations: *ApiKey* ###### path Parameters | | | | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | idrequired | string<uuid>The primary and unique identifier of the resource (inside tenant) according to [RFC 4122](https://www.rfc-editor.org/info/rfc4122). | ###### query Parameters | | | | ----------- | ---------------------------------------------------------------------------------------------------------------- | | did\_method | stringDefault:"web"Enum: "key" "web"All supported DID methods. Default is "web". | ###### Request Body schema: application/jsonrequired string < binary \> < base64 \> < application/octet-stream \> The unsigned presentation to sign. ##### Responses **200** The signed Verifiable Presentation. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **404** The schema represents an HTTP "Not Found" status code. **405** The schema represents an HTTP "Method Not Allowed" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. post/keys/{id}/presentations/sign URL for header-protected customer communication. https://api.truvity.{zone}/keys/{id}/presentations/sign URL for cookie-protected customer communication. https://docs.truvity.com/api/keys/{id}/presentations/sign ##### Request samples * Payload * Go * Java * TypeScript Content type application/json Copy `"string"` ##### Response samples * 200 * 400 * 401 * 403 * 404 * 405 * 429 * 500 * default Content type application/vp+ld+json Copy `"string"` #### [](#tag/keys/operation/KeyRestore)Restore Key. Restore Key's resource. ###### Authorizations: *ApiKey* ###### path Parameters | | | | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | idrequired | string<uuid>The primary and unique identifier of the resource (inside tenant) according to [RFC 4122](https://www.rfc-editor.org/info/rfc4122). | ###### header Parameters | | | | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Idempotency-Key | string\[ 32 .. 256 ] characters\[a-zA-Z0-9-]{32,256}From [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **Idempotency-Key** is a free identifier created by the client to identify a request. It is used by the service to identify repeated request to ensure idempotent behavior by sending the same (or a similar) response without executing the request a second time.Clients should be careful as any subsequent requests with the same key may return the same response without further check. Thus, it is recommended to use a UUID version 4 (random) or any other random string with enough entropy to avoid collisions.Keys expire after 24 hours. Clients are responsible to stay within this limit, if they require idempotent behavior.See [API Guideline Rule #181](https://opensource.zalando.com/restful-api-guidelines/#230) for further details. | | If-Matchrequired | stringFrom [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **If-Match** header field is used to declare a list of identifiers that are required to match the current resource version identifier in at least one position as a pre-condition for executing the request on the server side. This behavior is used to validate and reject optimistic updates, by checking if the resource version a consumer has based his changes on is outdated on arrival of the change request to prevent lost updates.If the pre-condition fails the server will respond with status code **412** (Precondition Failed). See [RFC 9110 Section 13.1.1](https://tools.ietf.org/html/rfc9110#section-13.1.1) as well as \[API Guideline Rule #182]\[api-182] for further details.\[api-182]: . | ##### Responses **200** Response with the restored Key. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **404** The schema represents an HTTP "Not Found" status code. **405** The schema represents an HTTP "Method Not Allowed" status code. **412** The schema represents an HTTP "Precondition Failed" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. post/keys/{id}/restore URL for header-protected customer communication. https://api.truvity.{zone}/keys/{id}/restore URL for cookie-protected customer communication. https://docs.truvity.com/api/keys/{id}/restore ##### Request samples * Go * Java * TypeScript Copy ##### Response samples * 200 * 400 * 401 * 403 * 404 * 405 * 412 * 429 * 500 * default Content type application/vnd.truvity.key+json;version=1 Copy Expand all Collapse all `{ "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "publicKeyBase58": "string", "publicKeyJwk": "crv: P-384\nkty: EC\nx: m2Gee3mEeKWmMuHiSUqeCrsqlWAHGG-Y8k4FoEhJjVl9zDpjGo3J0LrQAcL1Ns7K\n\"y\": 3FGUwlmVJznpuoBMWU68W1YIxGFx8usj23cR0miRGwGpZx3tQhx8CyG8JgX6BEnm\n\t\t", "publicKeyMultibase": "string", "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEm2Gee3mEeKWmMuHiSUqeCrsqlWAHGG+Y\n8k4FoEhJjVl9zDpjGo3J0LrQAcL1Ns7K3FGUwlmVJznpuoBMWU68W1YIxGFx8usj\n23cR0miRGwGpZx3tQhx8CyG8JgX6BEnm\n-----END PUBLIC KEY-----", "type": "ED25519" }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 }` #### [](#tag/keys/operation/KeyHistory)Read Key's history. History of the Key's resources. ###### Authorizations: *ApiKey* ###### path Parameters | | | | ---------- | ------------------------------------------------------------------- | | idrequired | string<uuid>The ID of the resource. | ###### header Parameters | | | | ------------- | ----------------------------------------------------- | | If-None-Match | stringThe ETag of the latest version of the resource. | ##### Responses **200** Response with the history of Key. **304** HTTP 304 - Not modified. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **404** The schema represents an HTTP "Not Found" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. get/keys/{id}/revisions URL for header-protected customer communication. https://api.truvity.{zone}/keys/{id}/revisions URL for cookie-protected customer communication. https://docs.truvity.com/api/keys/{id}/revisions ##### Request samples * Go * Java * TypeScript Copy ##### Response samples * 200 * 400 * 401 * 403 * 404 * 429 * 500 * default Content type application/json Copy Expand all Collapse all `{ "items": [ { "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "publicKeyBase58": "string", "publicKeyJwk": "crv: P-384\nkty: EC\nx: m2Gee3mEeKWmMuHiSUqeCrsqlWAHGG-Y8k4FoEhJjVl9zDpjGo3J0LrQAcL1Ns7K\n\"y\": 3FGUwlmVJznpuoBMWU68W1YIxGFx8usj23cR0miRGwGpZx3tQhx8CyG8JgX6BEnm\n\t\t", "publicKeyMultibase": "string", "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEm2Gee3mEeKWmMuHiSUqeCrsqlWAHGG+Y\n8k4FoEhJjVl9zDpjGo3J0LrQAcL1Ns7K3FGUwlmVJznpuoBMWU68W1YIxGFx8usj\n23cR0miRGwGpZx3tQhx8CyG8JgX6BEnm\n-----END PUBLIC KEY-----", "type": "ED25519" }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 } ] }` #### [](#tag/keys/operation/KeyRevision)Read the specific version of the Key. Read the specific version of the Key's resource. ###### Authorizations: *ApiKey* ###### path Parameters | | | | ---------------- | ----------------------------------------------------------------------------------------------------------- | | idrequired | string<uuid>The ID of the resource. | | revisionrequired | integer<int32>\[ 1 .. 999999 ]The revision of the resource. | ###### header Parameters | | | | ------------- | ----------------------------------------------------- | | If-None-Match | stringThe ETag of the latest version of the resource. | ##### Responses **200** The requested revision of the Key. **304** HTTP 304 - Not modified. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **404** The schema represents an HTTP "Not Found" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. get/keys/{id}/revisions/{revision} URL for header-protected customer communication. https://api.truvity.{zone}/keys/{id}/revisions/{revision} URL for cookie-protected customer communication. https://docs.truvity.com/api/keys/{id}/revisions/{revision} ##### Request samples * Go * Java * TypeScript Copy ##### Response samples * 200 * 400 * 401 * 403 * 404 * 429 * 500 * default Content type application/json Copy Expand all Collapse all `{ "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "publicKeyBase58": "string", "publicKeyJwk": "crv: P-384\nkty: EC\nx: m2Gee3mEeKWmMuHiSUqeCrsqlWAHGG-Y8k4FoEhJjVl9zDpjGo3J0LrQAcL1Ns7K\n\"y\": 3FGUwlmVJznpuoBMWU68W1YIxGFx8usj23cR0miRGwGpZx3tQhx8CyG8JgX6BEnm\n\t\t", "publicKeyMultibase": "string", "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEm2Gee3mEeKWmMuHiSUqeCrsqlWAHGG+Y\n8k4FoEhJjVl9zDpjGo3J0LrQAcL1Ns7K3FGUwlmVJznpuoBMWU68W1YIxGFx8usj\n23cR0miRGwGpZx3tQhx8CyG8JgX6BEnm\n-----END PUBLIC KEY-----", "type": "ED25519" }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 }` #### [](#tag/presentations)Presentation The API to manage Verifiable Presentations. #### [](#tag/presentations/operation/PresentationExport)Export Presentation. Generate an unsigned Verifiable Presentation in JSON-LD format from a list of Credentials. ###### Authorizations: *ApiKey* ###### Request Body schema: application/jsonrequired | | | | ------------------------- | ---------------------------------------------------------------------------------------------------------------------------- | | composition\_typerequired | stringValue: "EMBED" | | credential\_idsrequired | Array of strings<uuid>\[ 1 .. 64 ] items\[ items <uuid> ] | | holderrequired | string<uri>Just regular URI according to [RFC 3986](https://www.rfc-editor.org/rfc/rfc3986). | ##### Responses **200** The exported unsigned Verifiable Presentation. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. post/presentations/export URL for header-protected customer communication. https://api.truvity.{zone}/presentations/export URL for cookie-protected customer communication. https://docs.truvity.com/api/presentations/export ##### Request samples * Payload * Go * Java * TypeScript Content type application/json Copy Expand all Collapse all `{ "composition_type": "EMBED", "credential_ids": [ "497f6eca-6276-4993-bfeb-53cbbbba6f08" ], "holder": "http://example.com" }` ##### Response samples * 200 * 400 * 401 * 403 * 429 * 500 * default Content type application/vp+ld+json Copy `"string"` #### [](#tag/presentations/operation/PresentationImport)Import Presentation. Import a Verifiable Presentation's resource with **blob\_id**. To get **blob\_id** call [Upload](#tag/presentations/operation/PresentationUpload) first. ###### Authorizations: *ApiKey* ###### query Parameters | | | | ---------------- | ------------------------------------------------------------------------------------------------------- | | blob\_idrequired | string<uuid>The ID that returned on Upload operation in blob\_id field. | ###### header Parameters | | | | --------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Idempotency-Key | string\[ 32 .. 256 ] characters\[a-zA-Z0-9-]{32,256}From [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **Idempotency-Key** is a free identifier created by the client to identify a request. It is used by the service to identify repeated request to ensure idempotent behavior by sending the same (or a similar) response without executing the request a second time.Clients should be careful as any subsequent requests with the same key may return the same response without further check. Thus, it is recommended to use a UUID version 4 (random) or any other random string with enough entropy to avoid collisions.Keys expire after 24 hours. Clients are responsible to stay within this limit, if they require idempotent behavior.See [API Guideline Rule #181](https://opensource.zalando.com/restful-api-guidelines/#230) for further details. | ###### Request Body schema: application/jsonrequired | | | | ----------- | -------------------------------------- | | annotations | objectThe annotations of the resource. | | labels | objectThe labels of the resource. | ##### Responses **201** The imported Presentation. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **404** The schema represents an HTTP "Not Found" status code. **415** The schema represents an HTTP "Unsupported Media Type" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. post/presentations/import URL for header-protected customer communication. https://api.truvity.{zone}/presentations/import URL for cookie-protected customer communication. https://docs.truvity.com/api/presentations/import ##### Request samples * Payload * Go * Java * TypeScript Content type application/json Copy Expand all Collapse all `{ "annotations": { "property1": "string", "property2": "string" }, "labels": { "property1": "string", "property2": "string" } }` ##### Response samples * 201 * 400 * 401 * 403 * 404 * 415 * 429 * 500 * default Content type application/vnd.truvity.presentation+json;version=1 Copy Expand all Collapse all `{ "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "digest_multibase": "string", "id": "http://example.com", "linked_credential_refs": [ { "blob_id": "http://example.com", "digest_multibase": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f" } ], "type": [ "string" ] }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 }` #### [](#tag/presentations/operation/PresentationIssue)Issue Presentation. It's a handy call that wraps the following: 1. [Exporting](#tag/presentations/operation/PresentationExport) an unsigned JSON-LD representation of a Verifiable Presentation. 2. [Signing](#tag/keys/operation/PresentationSign) the created unsigned Presentation. 3. [Importing](#tag/presentations/operation/PresentationImport) the signed Presentation. ###### Authorizations: *ApiKey* ###### Request Body schema: application/jsonrequired | | | | ------------------------- | ---------------------------------------------------------------------------------------------------------------------------- | | composition\_typerequired | stringValue: "EMBED" | | credential\_idsrequired | Array of strings<uuid>\[ 1 .. 64 ] items\[ items <uuid> ] | | did\_method | stringDefault:"web"Enum: "key" "web"All supported DID methods. Default is "web". | | holder | string<uri>Just regular URI according to [RFC 3986](https://www.rfc-editor.org/rfc/rfc3986). | | key\_idrequired | string<uuid>The ID of the key to sign the credential. | ##### Responses **200** The issued Verifiable Presentation. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **405** The schema represents an HTTP "Method Not Allowed" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. post/presentations/issue URL for header-protected customer communication. https://api.truvity.{zone}/presentations/issue URL for cookie-protected customer communication. https://docs.truvity.com/api/presentations/issue ##### Request samples * Payload * Go * Java * TypeScript Content type application/json Copy Expand all Collapse all `{ "composition_type": "EMBED", "credential_ids": [ "497f6eca-6276-4993-bfeb-53cbbbba6f08" ], "did_method": "key", "holder": "http://example.com", "key_id": "1e779c8a-6786-4c89-b7c3-a6666f5fd6b5" }` ##### Response samples * 200 * 400 * 401 * 403 * 405 * 429 * 500 * default Content type application/vnd.truvity.presentation+json;version=1 Copy Expand all Collapse all `{ "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "digest_multibase": "string", "id": "http://example.com", "linked_credential_refs": [ { "blob_id": "http://example.com", "digest_multibase": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f" } ], "type": [ "string" ] }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 }` #### [](#tag/presentations/operation/PresentationSearch)Search for Presentations. Search for Presentations with extended filters capabilities. ###### Authorizations: *ApiKey* ###### Request Body schema: application/jsonrequired | | | | ------ | ------------------------------------------------------------------------------------------------------------------- | | filter | Array of objects (PresentationFilter)<= 4 itemsThe filter to apply to the search. | | sort | Array of objects (PresentationSort)<= 4 itemsThe sort order to apply to the search. | ##### Responses **200** The search results of Presentation. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **415** The schema represents an HTTP "Unsupported Media Type" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. post/presentations/search URL for header-protected customer communication. https://api.truvity.{zone}/presentations/search URL for cookie-protected customer communication. https://docs.truvity.com/api/presentations/search ##### Request samples * Payload * Go * Java * TypeScript Content type application/json Copy Expand all Collapse all `{ "filter": [ { "annotations": [ { "operator": "EQUAL", "key": "string", "value": "string" } ], "created_at": { "operator": "BETWEEN", "left": "2019-08-24T14:15:22Z", "right": "2019-08-24T14:15:22Z" }, "data": { "digest_multibase": { "operator": "EQUAL", "value": "string" }, "id": { "operator": "EQUAL", "value": "http://example.com" }, "type": { "operator": "IN", "values": [ "string" ] } }, "deleted_at": { "operator": "BETWEEN", "left": "2019-08-24T14:15:22Z", "right": "2019-08-24T14:15:22Z" }, "etag": { "operator": "EQUAL", "value": "string" }, "id": { "operator": "EQUAL", "value": "a860a344-d7b2-406e-828e-8d442f23f344" }, "labels": [ { "operator": "EQUAL", "key": "string", "value": "string" } ], "modified_at": { "operator": "BETWEEN", "left": "2019-08-24T14:15:22Z", "right": "2019-08-24T14:15:22Z" }, "revision": { "operator": "EQUAL", "value": 1 }, "linked_credentials": { "annotations": [ { "operator": "EQUAL", "key": "string", "value": "string" } ], "created_at": { "operator": "BETWEEN", "left": "2019-08-24T14:15:22Z", "right": "2019-08-24T14:15:22Z" }, "data": { "digest_multibase": { "operator": "EQUAL", "value": "string" }, "holder": { "operator": "EQUAL", "value": "http://example.com" }, "id": { "operator": "EQUAL", "value": "http://example.com" }, "issuer": { "operator": "EQUAL", "value": "http://example.com" }, "type": { "operator": "IN", "values": [ "string" ] }, "valid_from": { "operator": "BETWEEN", "left": "2019-08-24T14:15:22Z", "right": "2019-08-24T14:15:22Z" }, "valid_until": { "operator": "BETWEEN", "left": "2019-08-24T14:15:22Z", "right": "2019-08-24T14:15:22Z" } }, "deleted_at": { "operator": "BETWEEN", "left": "2019-08-24T14:15:22Z", "right": "2019-08-24T14:15:22Z" }, "etag": { "operator": "EQUAL", "value": "string" }, "id": { "operator": "EQUAL", "value": "a860a344-d7b2-406e-828e-8d442f23f344" }, "labels": [ { "operator": "EQUAL", "key": "string", "value": "string" } ], "modified_at": { "operator": "BETWEEN", "left": "2019-08-24T14:15:22Z", "right": "2019-08-24T14:15:22Z" }, "revision": { "operator": "EQUAL", "value": 1 } } } ], "sort": [ { "field": "DATA_TYPE", "order": "ASC" } ] }` ##### Response samples * 200 * 400 * 401 * 403 * 415 * 429 * 500 * default Content type application/json Copy Expand all Collapse all `{ "items": [ { "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "digest_multibase": "string", "id": "http://example.com", "linked_credential_refs": [ { "blob_id": "http://example.com", "digest_multibase": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f" } ], "type": [ "string" ] }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 } ] }` #### [](#tag/presentations/operation/PresentationUpload)Upload Presentation's blob. Initiates a Presentation blob upload, returning a pre-signed S3 URL. Response contains: * **blob\_id** (required for Presentation creation) * **upload\_uri** (pre-signed URL for upload) * **timeout** (expiration in seconds). ###### Authorizations: *ApiKey* ###### header Parameters | | | | --------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Idempotency-Key | string\[ 32 .. 256 ] characters\[a-zA-Z0-9-]{32,256}From [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **Idempotency-Key** is a free identifier created by the client to identify a request. It is used by the service to identify repeated request to ensure idempotent behavior by sending the same (or a similar) response without executing the request a second time.Clients should be careful as any subsequent requests with the same key may return the same response without further check. Thus, it is recommended to use a UUID version 4 (random) or any other random string with enough entropy to avoid collisions.Keys expire after 24 hours. Clients are responsible to stay within this limit, if they require idempotent behavior.See [API Guideline Rule #181](https://opensource.zalando.com/restful-api-guidelines/#230) for further details. | ##### Responses **200** The result of uploading of Presentation's resource. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. post/presentations/upload URL for header-protected customer communication. https://api.truvity.{zone}/presentations/upload URL for cookie-protected customer communication. https://docs.truvity.com/api/presentations/upload ##### Request samples * Go * Java * TypeScript Copy ##### Response samples * 200 * 400 * 401 * 403 * 429 * 500 * default Content type application/json Copy `{ "blob_id": "8249af2f-dd23-416e-b9c4-6cb13a792190", "timeout": 1, "upload_uri": "http://example.com" }` #### [](#tag/presentations/operation/PresentationDelete)Delete Presentation. Delete Presentation's resource. ###### Authorizations: *ApiKey* ###### path Parameters | | | | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | idrequired | string<uuid>The primary and unique identifier of the resource (inside tenant) according to [RFC 4122](https://www.rfc-editor.org/info/rfc4122). | ###### header Parameters | | | | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Idempotency-Key | string\[ 32 .. 256 ] characters\[a-zA-Z0-9-]{32,256}From [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **Idempotency-Key** is a free identifier created by the client to identify a request. It is used by the service to identify repeated request to ensure idempotent behavior by sending the same (or a similar) response without executing the request a second time.Clients should be careful as any subsequent requests with the same key may return the same response without further check. Thus, it is recommended to use a UUID version 4 (random) or any other random string with enough entropy to avoid collisions.Keys expire after 24 hours. Clients are responsible to stay within this limit, if they require idempotent behavior.See [API Guideline Rule #181](https://opensource.zalando.com/restful-api-guidelines/#230) for further details. | | If-Matchrequired | stringFrom [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **If-Match** header field is used to declare a list of identifiers that are required to match the current resource version identifier in at least one position as a pre-condition for executing the request on the server side. This behavior is used to validate and reject optimistic updates, by checking if the resource version a consumer has based his changes on is outdated on arrival of the change request to prevent lost updates.If the pre-condition fails the server will respond with status code **412** (Precondition Failed). See [RFC 9110 Section 13.1.1](https://tools.ietf.org/html/rfc9110#section-13.1.1) as well as \[API Guideline Rule #182]\[api-182] for further details.\[api-182]: . | ##### Responses **204** HTTP 204 - No content. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **404** The schema represents an HTTP "Not Found" status code. **405** The schema represents an HTTP "Method Not Allowed" status code. **412** The schema represents an HTTP "Precondition Failed" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. delete/presentations/{id} URL for header-protected customer communication. https://api.truvity.{zone}/presentations/{id} URL for cookie-protected customer communication. https://docs.truvity.com/api/presentations/{id} ##### Request samples * Go * Java * TypeScript Copy ##### Response samples * 400 * 401 * 403 * 404 * 405 * 412 * 429 * 500 * default Content type application/problem+json Example /bad-request/bad-request Copy Expand all Collapse all `{ "detail": "string", "errors": [ { "location": "string", "message": "string", "value": null } ], "instance": "http://example.com", "status": 100, "title": "string", "type": "/bad-request" }` #### [](#tag/presentations/operation/PresentationLatest)Get the latest version of Presentation. Get the latest version of Presentation. ###### Authorizations: *ApiKey* ###### path Parameters | | | | ---------- | ------------------------------------------------------------------- | | idrequired | string<uuid>The ID of the resource. | ###### header Parameters | | | | ------------- | ----------------------------------------------------- | | If-None-Match | stringThe ETag of the latest version of the resource. | ##### Responses **200** Response with the latest Presentation. **304** HTTP 304 - Not modified. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **404** The schema represents an HTTP "Not Found" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. get/presentations/{id} URL for header-protected customer communication. https://api.truvity.{zone}/presentations/{id} URL for cookie-protected customer communication. https://docs.truvity.com/api/presentations/{id} ##### Request samples * Go * Java * TypeScript Copy ##### Response samples * 200 * 400 * 401 * 403 * 404 * 429 * 500 * default Content type application/vnd.truvity.presentation+json;version=1 Copy Expand all Collapse all `{ "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "digest_multibase": "string", "id": "http://example.com", "linked_credential_refs": [ { "blob_id": "http://example.com", "digest_multibase": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f" } ], "type": [ "string" ] }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 }` #### [](#tag/presentations/operation/PresentationUpdateAnnotations)Update annotations. Update annotations of Presentation's resource. ###### Authorizations: *ApiKey* ###### path Parameters | | | | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | idrequired | string<uuid>The primary and unique identifier of the resource (inside tenant) according to [RFC 4122](https://www.rfc-editor.org/info/rfc4122). | ###### header Parameters | | | | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Idempotency-Key | string\[ 32 .. 256 ] characters\[a-zA-Z0-9-]{32,256}From [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **Idempotency-Key** is a free identifier created by the client to identify a request. It is used by the service to identify repeated request to ensure idempotent behavior by sending the same (or a similar) response without executing the request a second time.Clients should be careful as any subsequent requests with the same key may return the same response without further check. Thus, it is recommended to use a UUID version 4 (random) or any other random string with enough entropy to avoid collisions.Keys expire after 24 hours. Clients are responsible to stay within this limit, if they require idempotent behavior.See [API Guideline Rule #181](https://opensource.zalando.com/restful-api-guidelines/#230) for further details. | | If-Matchrequired | stringFrom [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **If-Match** header field is used to declare a list of identifiers that are required to match the current resource version identifier in at least one position as a pre-condition for executing the request on the server side. This behavior is used to validate and reject optimistic updates, by checking if the resource version a consumer has based his changes on is outdated on arrival of the change request to prevent lost updates.If the pre-condition fails the server will respond with status code **412** (Precondition Failed). See [RFC 9110 Section 13.1.1](https://tools.ietf.org/html/rfc9110#section-13.1.1) as well as \[API Guideline Rule #182]\[api-182] for further details.\[api-182]: . | ###### Request Body schema: application/jsonrequired | | | | ----------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------- | | annotationsrequired | objectThe annotations of the resource. | | property name\* additional property string <= 128 characters ^\[^\n]{0,128}$ Value of the resource annotation. | | ##### Responses **200** Response with the updated Presentation. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **404** The schema represents an HTTP "Not Found" status code. **405** The schema represents an HTTP "Method Not Allowed" status code. **412** The schema represents an HTTP "Precondition Failed" status code. **415** The schema represents an HTTP "Unsupported Media Type" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. patch/presentations/{id}/annotations URL for header-protected customer communication. https://api.truvity.{zone}/presentations/{id}/annotations URL for cookie-protected customer communication. https://docs.truvity.com/api/presentations/{id}/annotations ##### Request samples * Payload * Go * Java * TypeScript Content type application/json Copy Expand all Collapse all `{ "annotations": { "property1": "string", "property2": "string" } }` ##### Response samples * 200 * 400 * 401 * 403 * 404 * 405 * 412 * 415 * 429 * 500 * default Content type application/vnd.truvity.presentation+json;version=1 Copy Expand all Collapse all `{ "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "digest_multibase": "string", "id": "http://example.com", "linked_credential_refs": [ { "blob_id": "http://example.com", "digest_multibase": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f" } ], "type": [ "string" ] }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 }` #### [](#tag/presentations/operation/PresentationUpdateLabels)Update labels. Update labels of Presentation's resource. ###### Authorizations: *ApiKey* ###### path Parameters | | | | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | idrequired | string<uuid>The primary and unique identifier of the resource (inside tenant) according to [RFC 4122](https://www.rfc-editor.org/info/rfc4122). | ###### header Parameters | | | | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Idempotency-Key | string\[ 32 .. 256 ] characters\[a-zA-Z0-9-]{32,256}From [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **Idempotency-Key** is a free identifier created by the client to identify a request. It is used by the service to identify repeated request to ensure idempotent behavior by sending the same (or a similar) response without executing the request a second time.Clients should be careful as any subsequent requests with the same key may return the same response without further check. Thus, it is recommended to use a UUID version 4 (random) or any other random string with enough entropy to avoid collisions.Keys expire after 24 hours. Clients are responsible to stay within this limit, if they require idempotent behavior.See [API Guideline Rule #181](https://opensource.zalando.com/restful-api-guidelines/#230) for further details. | | If-Matchrequired | stringFrom [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **If-Match** header field is used to declare a list of identifiers that are required to match the current resource version identifier in at least one position as a pre-condition for executing the request on the server side. This behavior is used to validate and reject optimistic updates, by checking if the resource version a consumer has based his changes on is outdated on arrival of the change request to prevent lost updates.If the pre-condition fails the server will respond with status code **412** (Precondition Failed). See [RFC 9110 Section 13.1.1](https://tools.ietf.org/html/rfc9110#section-13.1.1) as well as \[API Guideline Rule #182]\[api-182] for further details.\[api-182]: . | ###### Request Body schema: application/jsonrequired | | | | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------- | | labelsrequired | objectThe labels of the resource. | | property name\* additional property string <= 63 characters ^(?:\[a-zA-Z0-9]\(?:\[a-zA-Z0-9\\.\\-\_]{0,61}\[a-zA...Show pattern Value of the resource label. | | ##### Responses **200** Response with the updated Presentation. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **404** The schema represents an HTTP "Not Found" status code. **405** The schema represents an HTTP "Method Not Allowed" status code. **412** The schema represents an HTTP "Precondition Failed" status code. **415** The schema represents an HTTP "Unsupported Media Type" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. patch/presentations/{id}/labels URL for header-protected customer communication. https://api.truvity.{zone}/presentations/{id}/labels URL for cookie-protected customer communication. https://docs.truvity.com/api/presentations/{id}/labels ##### Request samples * Payload * Go * Java * TypeScript Content type application/json Copy Expand all Collapse all `{ "labels": { "property1": "string", "property2": "string" } }` ##### Response samples * 200 * 400 * 401 * 403 * 404 * 405 * 412 * 415 * 429 * 500 * default Content type application/vnd.truvity.presentation+json;version=1 Copy Expand all Collapse all `{ "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "digest_multibase": "string", "id": "http://example.com", "linked_credential_refs": [ { "blob_id": "http://example.com", "digest_multibase": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f" } ], "type": [ "string" ] }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 }` #### [](#tag/presentations/operation/PresentationRestore)Restore Presentation. Restore Presentation's resource. ###### Authorizations: *ApiKey* ###### path Parameters | | | | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | idrequired | string<uuid>The primary and unique identifier of the resource (inside tenant) according to [RFC 4122](https://www.rfc-editor.org/info/rfc4122). | ###### header Parameters | | | | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Idempotency-Key | string\[ 32 .. 256 ] characters\[a-zA-Z0-9-]{32,256}From [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **Idempotency-Key** is a free identifier created by the client to identify a request. It is used by the service to identify repeated request to ensure idempotent behavior by sending the same (or a similar) response without executing the request a second time.Clients should be careful as any subsequent requests with the same key may return the same response without further check. Thus, it is recommended to use a UUID version 4 (random) or any other random string with enough entropy to avoid collisions.Keys expire after 24 hours. Clients are responsible to stay within this limit, if they require idempotent behavior.See [API Guideline Rule #181](https://opensource.zalando.com/restful-api-guidelines/#230) for further details. | | If-Matchrequired | stringFrom [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **If-Match** header field is used to declare a list of identifiers that are required to match the current resource version identifier in at least one position as a pre-condition for executing the request on the server side. This behavior is used to validate and reject optimistic updates, by checking if the resource version a consumer has based his changes on is outdated on arrival of the change request to prevent lost updates.If the pre-condition fails the server will respond with status code **412** (Precondition Failed). See [RFC 9110 Section 13.1.1](https://tools.ietf.org/html/rfc9110#section-13.1.1) as well as \[API Guideline Rule #182]\[api-182] for further details.\[api-182]: . | ##### Responses **200** Response with the restored Presentation. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **404** The schema represents an HTTP "Not Found" status code. **405** The schema represents an HTTP "Method Not Allowed" status code. **412** The schema represents an HTTP "Precondition Failed" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. post/presentations/{id}/restore URL for header-protected customer communication. https://api.truvity.{zone}/presentations/{id}/restore URL for cookie-protected customer communication. https://docs.truvity.com/api/presentations/{id}/restore ##### Request samples * Go * Java * TypeScript Copy ##### Response samples * 200 * 400 * 401 * 403 * 404 * 405 * 412 * 429 * 500 * default Content type application/vnd.truvity.presentation+json;version=1 Copy Expand all Collapse all `{ "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "digest_multibase": "string", "id": "http://example.com", "linked_credential_refs": [ { "blob_id": "http://example.com", "digest_multibase": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f" } ], "type": [ "string" ] }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 }` #### [](#tag/presentations/operation/PresentationHistory)Read Presentation's history. History of the Presentation's resources. ###### Authorizations: *ApiKey* ###### path Parameters | | | | ---------- | ------------------------------------------------------------------- | | idrequired | string<uuid>The ID of the resource. | ###### header Parameters | | | | ------------- | ----------------------------------------------------- | | If-None-Match | stringThe ETag of the latest version of the resource. | ##### Responses **200** Response with the history of Presentation. **304** HTTP 304 - Not modified. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **404** The schema represents an HTTP "Not Found" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. get/presentations/{id}/revisions URL for header-protected customer communication. https://api.truvity.{zone}/presentations/{id}/revisions URL for cookie-protected customer communication. https://docs.truvity.com/api/presentations/{id}/revisions ##### Request samples * Go * Java * TypeScript Copy ##### Response samples * 200 * 400 * 401 * 403 * 404 * 429 * 500 * default Content type application/json Copy Expand all Collapse all `{ "items": [ { "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "digest_multibase": "string", "id": "http://example.com", "linked_credential_refs": [ { "blob_id": "http://example.com", "digest_multibase": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f" } ], "type": [ "string" ] }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 } ] }` #### [](#tag/presentations/operation/PresentationRevision)Read the specific version of the Presentation. Read the specific version of the Presentation's resource. ###### Authorizations: *ApiKey* ###### path Parameters | | | | ---------------- | ----------------------------------------------------------------------------------------------------------- | | idrequired | string<uuid>The ID of the resource. | | revisionrequired | integer<int32>\[ 1 .. 999999 ]The revision of the resource. | ###### header Parameters | | | | ------------- | ----------------------------------------------------- | | If-None-Match | stringThe ETag of the latest version of the resource. | ##### Responses **200** The requested revision of the Presentation. **304** HTTP 304 - Not modified. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **404** The schema represents an HTTP "Not Found" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. get/presentations/{id}/revisions/{revision} URL for header-protected customer communication. https://api.truvity.{zone}/presentations/{id}/revisions/{revision} URL for cookie-protected customer communication. https://docs.truvity.com/api/presentations/{id}/revisions/{revision} ##### Request samples * Go * Java * TypeScript Copy ##### Response samples * 200 * 400 * 401 * 403 * 404 * 429 * 500 * default Content type application/json Copy Expand all Collapse all `{ "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "digest_multibase": "string", "id": "http://example.com", "linked_credential_refs": [ { "blob_id": "http://example.com", "digest_multibase": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f" } ], "type": [ "string" ] }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 }` #### [](#tag/presentations/operation/PresentationDownload)Download of Presentation's blob. Download of Presentation's blob. ###### Authorizations: *ApiKey* ###### path Parameters | | | | ---------------- | ----------------------------------------------------------------------------------------------------------- | | idrequired | string<uuid>The ID of the resource. | | revisionrequired | integer<int32>\[ 1 .. 999999 ]The revision of the resource. | ###### header Parameters | | | | ------------- | ----------------------------------------------------- | | If-None-Match | stringThe ETag of the latest version of the resource. | ##### Responses **200** The result of downloading of Presentation's resource. **304** HTTP 304 - Not modified. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **404** The schema represents an HTTP "Not Found" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. get/presentations/{id}/revisions/{revision}/download URL for header-protected customer communication. https://api.truvity.{zone}/presentations/{id}/revisions/{revision}/download URL for cookie-protected customer communication. https://docs.truvity.com/api/presentations/{id}/revisions/{revision}/download ##### Request samples * Go * Java * TypeScript Copy ##### Response samples * 200 * 400 * 401 * 403 * 404 * 429 * 500 * default Content type application/vp+ld+json Copy `"string"` #### [](#tag/presentations/operation/PresentationVerify)Verify Presentation. Verify a Verifiable Presentation. ###### Authorizations: *ApiKey* ###### path Parameters | | | | ---------- | ------------------------------------------------------------------- | | idrequired | string<uuid>The ID of the resource. | ##### Responses **200** The verification result. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. get/presentations/{id}/verify URL for header-protected customer communication. https://api.truvity.{zone}/presentations/{id}/verify URL for cookie-protected customer communication. https://docs.truvity.com/api/presentations/{id}/verify ##### Request samples * Go * Java * TypeScript Copy ##### Response samples * 200 * 400 * 401 * 403 * 429 * 500 * default Content type application/json Copy `{ "verified": true }` #### [](#tag/published-schemas)Published Credential Schema The API to manage Truvity's published credential schemas. #### [](#tag/published-schemas/operation/PublishedSchemaSearch)Search for PublishedSchemas. Search for PublishedSchemas with extended filters capabilities. ###### Authorizations: *ApiKey* ###### Request Body schema: application/jsonrequired | | | | ------ | ---------------------------------------------------------------------------------------------------------------------- | | filter | Array of objects (PublishedSchemaFilter)<= 4 itemsThe filter to apply to the search. | | sort | Array of objects (PublishedSchemaSort)<= 4 itemsThe sort order to apply to the search. | ##### Responses **200** The search results of PublishedSchema. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **415** The schema represents an HTTP "Unsupported Media Type" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. post/published-schemas/search URL for header-protected customer communication. https://api.truvity.{zone}/published-schemas/search URL for cookie-protected customer communication. https://docs.truvity.com/api/published-schemas/search ##### Request samples * Payload * Go * Java * TypeScript Content type application/json Copy Expand all Collapse all `{ "filter": [ { "annotations": [ { "operator": "EQUAL", "key": "string", "value": "string" } ], "created_at": { "operator": "BETWEEN", "left": "2019-08-24T14:15:22Z", "right": "2019-08-24T14:15:22Z" }, "data": { "digest_multibase": { "operator": "EQUAL", "value": "string" }, "published_at": { "operator": "BETWEEN", "left": "2019-08-24T14:15:22Z", "right": "2019-08-24T14:15:22Z" }, "slug": { "operator": "EQUAL", "value": "string" }, "version": { "operator": "EQUAL", "value": 1 } }, "deleted_at": { "operator": "BETWEEN", "left": "2019-08-24T14:15:22Z", "right": "2019-08-24T14:15:22Z" }, "etag": { "operator": "EQUAL", "value": "string" }, "id": { "operator": "EQUAL", "value": "a860a344-d7b2-406e-828e-8d442f23f344" }, "labels": [ { "operator": "EQUAL", "key": "string", "value": "string" } ], "modified_at": { "operator": "BETWEEN", "left": "2019-08-24T14:15:22Z", "right": "2019-08-24T14:15:22Z" }, "revision": { "operator": "EQUAL", "value": 1 } } ], "sort": [ { "field": "DATA_PUBLISHED_AT", "order": "ASC" } ] }` ##### Response samples * 200 * 400 * 401 * 403 * 415 * 429 * 500 * default Content type application/json Copy Expand all Collapse all `{ "items": [ { "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "digest_multibase": "string", "json_ld_vocab_digest_multibase": "string", "json_ld_vocab_url": "http://example.com", "json_schema_digest_multibase": "string", "json_schema_url": "http://example.com", "published_at": "2019-08-24T14:15:22Z", "schema": { "fields": [ { "kind": "BOOLEAN", "is_array": true, "json_ld_iri": "string", "json_ld_type": "string", "name": "string", "not_empty": true, "title": "string" } ], "json_ld_base_iri": "string", "json_ld_iri": "string", "json_ld_relative_iri_delimiter": "string", "json_ld_term_name": "string" }, "slug": "string", "url": "http://example.com", "vcdm_json_schema_digest_multibase": "string", "vcdm_json_schema_url": "http://example.com", "version": 1 }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 } ] }` #### [](#tag/published-schemas/operation/PublishedSchemaDelete)Delete PublishedSchema. Delete PublishedSchema's resource. ###### Authorizations: *ApiKey* ###### path Parameters | | | | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | idrequired | string<uuid>The primary and unique identifier of the resource (inside tenant) according to [RFC 4122](https://www.rfc-editor.org/info/rfc4122). | ###### header Parameters | | | | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Idempotency-Key | string\[ 32 .. 256 ] characters\[a-zA-Z0-9-]{32,256}From [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **Idempotency-Key** is a free identifier created by the client to identify a request. It is used by the service to identify repeated request to ensure idempotent behavior by sending the same (or a similar) response without executing the request a second time.Clients should be careful as any subsequent requests with the same key may return the same response without further check. Thus, it is recommended to use a UUID version 4 (random) or any other random string with enough entropy to avoid collisions.Keys expire after 24 hours. Clients are responsible to stay within this limit, if they require idempotent behavior.See [API Guideline Rule #181](https://opensource.zalando.com/restful-api-guidelines/#230) for further details. | | If-Matchrequired | stringFrom [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **If-Match** header field is used to declare a list of identifiers that are required to match the current resource version identifier in at least one position as a pre-condition for executing the request on the server side. This behavior is used to validate and reject optimistic updates, by checking if the resource version a consumer has based his changes on is outdated on arrival of the change request to prevent lost updates.If the pre-condition fails the server will respond with status code **412** (Precondition Failed). See [RFC 9110 Section 13.1.1](https://tools.ietf.org/html/rfc9110#section-13.1.1) as well as \[API Guideline Rule #182]\[api-182] for further details.\[api-182]: . | ##### Responses **204** HTTP 204 - No content. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **404** The schema represents an HTTP "Not Found" status code. **405** The schema represents an HTTP "Method Not Allowed" status code. **412** The schema represents an HTTP "Precondition Failed" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. delete/published-schemas/{id} URL for header-protected customer communication. https://api.truvity.{zone}/published-schemas/{id} URL for cookie-protected customer communication. https://docs.truvity.com/api/published-schemas/{id} ##### Request samples * Go * Java * TypeScript Copy ##### Response samples * 400 * 401 * 403 * 404 * 405 * 412 * 429 * 500 * default Content type application/problem+json Example /bad-request/bad-request Copy Expand all Collapse all `{ "detail": "string", "errors": [ { "location": "string", "message": "string", "value": null } ], "instance": "http://example.com", "status": 100, "title": "string", "type": "/bad-request" }` #### [](#tag/published-schemas/operation/PublishedSchemaLatest)Get the latest version of PublishedSchema. Get the latest version of PublishedSchema. ###### Authorizations: *ApiKey* ###### path Parameters | | | | ---------- | ------------------------------------------------------------------- | | idrequired | string<uuid>The ID of the resource. | ###### header Parameters | | | | ------------- | ----------------------------------------------------- | | If-None-Match | stringThe ETag of the latest version of the resource. | ##### Responses **200** Response with the latest PublishedSchema. **304** HTTP 304 - Not modified. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **404** The schema represents an HTTP "Not Found" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. get/published-schemas/{id} URL for header-protected customer communication. https://api.truvity.{zone}/published-schemas/{id} URL for cookie-protected customer communication. https://docs.truvity.com/api/published-schemas/{id} ##### Request samples * Go * Java * TypeScript Copy ##### Response samples * 200 * 400 * 401 * 403 * 404 * 429 * 500 * default Content type application/vnd.truvity.published-schema+json;version=1 Copy Expand all Collapse all `{ "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "digest_multibase": "string", "json_ld_vocab_digest_multibase": "string", "json_ld_vocab_url": "http://example.com", "json_schema_digest_multibase": "string", "json_schema_url": "http://example.com", "published_at": "2019-08-24T14:15:22Z", "schema": { "fields": [ { "kind": "BOOLEAN", "is_array": true, "json_ld_iri": "string", "json_ld_type": "string", "name": "string", "not_empty": true, "title": "string" } ], "json_ld_base_iri": "string", "json_ld_iri": "string", "json_ld_relative_iri_delimiter": "string", "json_ld_term_name": "string" }, "slug": "string", "url": "http://example.com", "vcdm_json_schema_digest_multibase": "string", "vcdm_json_schema_url": "http://example.com", "version": 1 }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 }` #### [](#tag/published-schemas/operation/PublishedSchemaUpdateAnnotations)Update annotations. Update annotations of PublishedSchema's resource. ###### Authorizations: *ApiKey* ###### path Parameters | | | | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | idrequired | string<uuid>The primary and unique identifier of the resource (inside tenant) according to [RFC 4122](https://www.rfc-editor.org/info/rfc4122). | ###### header Parameters | | | | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Idempotency-Key | string\[ 32 .. 256 ] characters\[a-zA-Z0-9-]{32,256}From [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **Idempotency-Key** is a free identifier created by the client to identify a request. It is used by the service to identify repeated request to ensure idempotent behavior by sending the same (or a similar) response without executing the request a second time.Clients should be careful as any subsequent requests with the same key may return the same response without further check. Thus, it is recommended to use a UUID version 4 (random) or any other random string with enough entropy to avoid collisions.Keys expire after 24 hours. Clients are responsible to stay within this limit, if they require idempotent behavior.See [API Guideline Rule #181](https://opensource.zalando.com/restful-api-guidelines/#230) for further details. | | If-Matchrequired | stringFrom [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **If-Match** header field is used to declare a list of identifiers that are required to match the current resource version identifier in at least one position as a pre-condition for executing the request on the server side. This behavior is used to validate and reject optimistic updates, by checking if the resource version a consumer has based his changes on is outdated on arrival of the change request to prevent lost updates.If the pre-condition fails the server will respond with status code **412** (Precondition Failed). See [RFC 9110 Section 13.1.1](https://tools.ietf.org/html/rfc9110#section-13.1.1) as well as \[API Guideline Rule #182]\[api-182] for further details.\[api-182]: . | ###### Request Body schema: application/jsonrequired | | | | ----------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------- | | annotationsrequired | objectThe annotations of the resource. | | property name\* additional property string <= 128 characters ^\[^\n]{0,128}$ Value of the resource annotation. | | ##### Responses **200** Response with the updated PublishedSchema. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **404** The schema represents an HTTP "Not Found" status code. **405** The schema represents an HTTP "Method Not Allowed" status code. **412** The schema represents an HTTP "Precondition Failed" status code. **415** The schema represents an HTTP "Unsupported Media Type" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. patch/published-schemas/{id}/annotations URL for header-protected customer communication. https://api.truvity.{zone}/published-schemas/{id}/annotations URL for cookie-protected customer communication. https://docs.truvity.com/api/published-schemas/{id}/annotations ##### Request samples * Payload * Go * Java * TypeScript Content type application/json Copy Expand all Collapse all `{ "annotations": { "property1": "string", "property2": "string" } }` ##### Response samples * 200 * 400 * 401 * 403 * 404 * 405 * 412 * 415 * 429 * 500 * default Content type application/vnd.truvity.published-schema+json;version=1 Copy Expand all Collapse all `{ "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "digest_multibase": "string", "json_ld_vocab_digest_multibase": "string", "json_ld_vocab_url": "http://example.com", "json_schema_digest_multibase": "string", "json_schema_url": "http://example.com", "published_at": "2019-08-24T14:15:22Z", "schema": { "fields": [ { "kind": "BOOLEAN", "is_array": true, "json_ld_iri": "string", "json_ld_type": "string", "name": "string", "not_empty": true, "title": "string" } ], "json_ld_base_iri": "string", "json_ld_iri": "string", "json_ld_relative_iri_delimiter": "string", "json_ld_term_name": "string" }, "slug": "string", "url": "http://example.com", "vcdm_json_schema_digest_multibase": "string", "vcdm_json_schema_url": "http://example.com", "version": 1 }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 }` #### [](#tag/published-schemas/operation/PublishedSchemaUpdateLabels)Update labels. Update labels of PublishedSchema's resource. ###### Authorizations: *ApiKey* ###### path Parameters | | | | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | idrequired | string<uuid>The primary and unique identifier of the resource (inside tenant) according to [RFC 4122](https://www.rfc-editor.org/info/rfc4122). | ###### header Parameters | | | | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Idempotency-Key | string\[ 32 .. 256 ] characters\[a-zA-Z0-9-]{32,256}From [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **Idempotency-Key** is a free identifier created by the client to identify a request. It is used by the service to identify repeated request to ensure idempotent behavior by sending the same (or a similar) response without executing the request a second time.Clients should be careful as any subsequent requests with the same key may return the same response without further check. Thus, it is recommended to use a UUID version 4 (random) or any other random string with enough entropy to avoid collisions.Keys expire after 24 hours. Clients are responsible to stay within this limit, if they require idempotent behavior.See [API Guideline Rule #181](https://opensource.zalando.com/restful-api-guidelines/#230) for further details. | | If-Matchrequired | stringFrom [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **If-Match** header field is used to declare a list of identifiers that are required to match the current resource version identifier in at least one position as a pre-condition for executing the request on the server side. This behavior is used to validate and reject optimistic updates, by checking if the resource version a consumer has based his changes on is outdated on arrival of the change request to prevent lost updates.If the pre-condition fails the server will respond with status code **412** (Precondition Failed). See [RFC 9110 Section 13.1.1](https://tools.ietf.org/html/rfc9110#section-13.1.1) as well as \[API Guideline Rule #182]\[api-182] for further details.\[api-182]: . | ###### Request Body schema: application/jsonrequired | | | | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------- | | labelsrequired | objectThe labels of the resource. | | property name\* additional property string <= 63 characters ^(?:\[a-zA-Z0-9]\(?:\[a-zA-Z0-9\\.\\-\_]{0,61}\[a-zA...Show pattern Value of the resource label. | | ##### Responses **200** Response with the updated PublishedSchema. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **404** The schema represents an HTTP "Not Found" status code. **405** The schema represents an HTTP "Method Not Allowed" status code. **412** The schema represents an HTTP "Precondition Failed" status code. **415** The schema represents an HTTP "Unsupported Media Type" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. patch/published-schemas/{id}/labels URL for header-protected customer communication. https://api.truvity.{zone}/published-schemas/{id}/labels URL for cookie-protected customer communication. https://docs.truvity.com/api/published-schemas/{id}/labels ##### Request samples * Payload * Go * Java * TypeScript Content type application/json Copy Expand all Collapse all `{ "labels": { "property1": "string", "property2": "string" } }` ##### Response samples * 200 * 400 * 401 * 403 * 404 * 405 * 412 * 415 * 429 * 500 * default Content type application/vnd.truvity.published-schema+json;version=1 Copy Expand all Collapse all `{ "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "digest_multibase": "string", "json_ld_vocab_digest_multibase": "string", "json_ld_vocab_url": "http://example.com", "json_schema_digest_multibase": "string", "json_schema_url": "http://example.com", "published_at": "2019-08-24T14:15:22Z", "schema": { "fields": [ { "kind": "BOOLEAN", "is_array": true, "json_ld_iri": "string", "json_ld_type": "string", "name": "string", "not_empty": true, "title": "string" } ], "json_ld_base_iri": "string", "json_ld_iri": "string", "json_ld_relative_iri_delimiter": "string", "json_ld_term_name": "string" }, "slug": "string", "url": "http://example.com", "vcdm_json_schema_digest_multibase": "string", "vcdm_json_schema_url": "http://example.com", "version": 1 }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 }` #### [](#tag/published-schemas/operation/PublishedSchemaRestore)Restore PublishedSchema. Restore PublishedSchema's resource. ###### Authorizations: *ApiKey* ###### path Parameters | | | | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | idrequired | string<uuid>The primary and unique identifier of the resource (inside tenant) according to [RFC 4122](https://www.rfc-editor.org/info/rfc4122). | ###### header Parameters | | | | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Idempotency-Key | string\[ 32 .. 256 ] characters\[a-zA-Z0-9-]{32,256}From [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **Idempotency-Key** is a free identifier created by the client to identify a request. It is used by the service to identify repeated request to ensure idempotent behavior by sending the same (or a similar) response without executing the request a second time.Clients should be careful as any subsequent requests with the same key may return the same response without further check. Thus, it is recommended to use a UUID version 4 (random) or any other random string with enough entropy to avoid collisions.Keys expire after 24 hours. Clients are responsible to stay within this limit, if they require idempotent behavior.See [API Guideline Rule #181](https://opensource.zalando.com/restful-api-guidelines/#230) for further details. | | If-Matchrequired | stringFrom [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **If-Match** header field is used to declare a list of identifiers that are required to match the current resource version identifier in at least one position as a pre-condition for executing the request on the server side. This behavior is used to validate and reject optimistic updates, by checking if the resource version a consumer has based his changes on is outdated on arrival of the change request to prevent lost updates.If the pre-condition fails the server will respond with status code **412** (Precondition Failed). See [RFC 9110 Section 13.1.1](https://tools.ietf.org/html/rfc9110#section-13.1.1) as well as \[API Guideline Rule #182]\[api-182] for further details.\[api-182]: . | ##### Responses **200** Response with the restored PublishedSchema. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **404** The schema represents an HTTP "Not Found" status code. **405** The schema represents an HTTP "Method Not Allowed" status code. **412** The schema represents an HTTP "Precondition Failed" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. post/published-schemas/{id}/restore URL for header-protected customer communication. https://api.truvity.{zone}/published-schemas/{id}/restore URL for cookie-protected customer communication. https://docs.truvity.com/api/published-schemas/{id}/restore ##### Request samples * Go * Java * TypeScript Copy ##### Response samples * 200 * 400 * 401 * 403 * 404 * 405 * 412 * 429 * 500 * default Content type application/vnd.truvity.published-schema+json;version=1 Copy Expand all Collapse all `{ "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "digest_multibase": "string", "json_ld_vocab_digest_multibase": "string", "json_ld_vocab_url": "http://example.com", "json_schema_digest_multibase": "string", "json_schema_url": "http://example.com", "published_at": "2019-08-24T14:15:22Z", "schema": { "fields": [ { "kind": "BOOLEAN", "is_array": true, "json_ld_iri": "string", "json_ld_type": "string", "name": "string", "not_empty": true, "title": "string" } ], "json_ld_base_iri": "string", "json_ld_iri": "string", "json_ld_relative_iri_delimiter": "string", "json_ld_term_name": "string" }, "slug": "string", "url": "http://example.com", "vcdm_json_schema_digest_multibase": "string", "vcdm_json_schema_url": "http://example.com", "version": 1 }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 }` #### [](#tag/published-schemas/operation/PublishedSchemaRevision)Read the specific version of the PublishedSchema. Read the specific version of the PublishedSchema's resource. ###### Authorizations: *ApiKey* ###### path Parameters | | | | ---------------- | ----------------------------------------------------------------------------------------------------------- | | idrequired | string<uuid>The ID of the resource. | | revisionrequired | integer<int32>\[ 1 .. 999999 ]The revision of the resource. | ###### header Parameters | | | | ------------- | ----------------------------------------------------- | | If-None-Match | stringThe ETag of the latest version of the resource. | ##### Responses **200** The requested revision of the PublishedSchema. **304** HTTP 304 - Not modified. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **404** The schema represents an HTTP "Not Found" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. get/published-schemas/{id}/revisions/{revision} URL for header-protected customer communication. https://api.truvity.{zone}/published-schemas/{id}/revisions/{revision} URL for cookie-protected customer communication. https://docs.truvity.com/api/published-schemas/{id}/revisions/{revision} ##### Request samples * Go * Java * TypeScript Copy ##### Response samples * 200 * 400 * 401 * 403 * 404 * 429 * 500 * default Content type application/json Copy Expand all Collapse all `{ "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "digest_multibase": "string", "json_ld_vocab_digest_multibase": "string", "json_ld_vocab_url": "http://example.com", "json_schema_digest_multibase": "string", "json_schema_url": "http://example.com", "published_at": "2019-08-24T14:15:22Z", "schema": { "fields": [ { "kind": "BOOLEAN", "is_array": true, "json_ld_iri": "string", "json_ld_type": "string", "name": "string", "not_empty": true, "title": "string" } ], "json_ld_base_iri": "string", "json_ld_iri": "string", "json_ld_relative_iri_delimiter": "string", "json_ld_term_name": "string" }, "slug": "string", "url": "http://example.com", "vcdm_json_schema_digest_multibase": "string", "vcdm_json_schema_url": "http://example.com", "version": 1 }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 }` #### [](#tag/schemas)Credential Schema The API to manage Credential schemas. #### [](#tag/schemas/operation/SchemaCreate)Create Schema. Creates Schema's resource. ###### Authorizations: *ApiKey* ###### header Parameters | | | | --------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Idempotency-Key | string\[ 32 .. 256 ] characters\[a-zA-Z0-9-]{32,256}From [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **Idempotency-Key** is a free identifier created by the client to identify a request. It is used by the service to identify repeated request to ensure idempotent behavior by sending the same (or a similar) response without executing the request a second time.Clients should be careful as any subsequent requests with the same key may return the same response without further check. Thus, it is recommended to use a UUID version 4 (random) or any other random string with enough entropy to avoid collisions.Keys expire after 24 hours. Clients are responsible to stay within this limit, if they require idempotent behavior.See [API Guideline Rule #181](https://opensource.zalando.com/restful-api-guidelines/#230) for further details. | ###### Request Body schema: application/jsonrequired | | | | ------------ | ---------------------------------------------------------------------------------------------- | | annotations | objectThe annotations of the resource. | | datarequired | object (CredentialSchemaCreate)The schema for creating a new CredentialSchema. | | labels | objectThe labels of the resource. | ##### Responses **201** Response with the newly created Schema. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **415** The schema represents an HTTP "Unsupported Media Type" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. post/schemas URL for header-protected customer communication. https://api.truvity.{zone}/schemas URL for cookie-protected customer communication. https://docs.truvity.com/api/schemas ##### Request samples * Payload * Go * Java * TypeScript Content type application/json Copy Expand all Collapse all `{ "annotations": { "property1": "string", "property2": "string" }, "data": { "from_published_schema_url": "http://example.com", "from_schema": "5b2f1b7c-e766-4791-9633-8d5200b742cc", "schema": { "fields": [ { "kind": "BOOLEAN", "is_array": true, "json_ld_iri": "string", "json_ld_type": "string", "name": "string", "not_empty": true, "title": "string" } ], "json_ld_base_iri": "string", "json_ld_iri": "string", "json_ld_relative_iri_delimiter": "string", "json_ld_term_name": "string" } }, "labels": { "property1": "string", "property2": "string" } }` ##### Response samples * 201 * 400 * 401 * 403 * 415 * 429 * 500 * default Content type application/vnd.truvity.schema+json;version=1 Copy Expand all Collapse all `{ "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "digest_multibase": "string", "schema": { "fields": [ { "kind": "BOOLEAN", "is_array": true, "json_ld_iri": "string", "json_ld_type": "string", "name": "string", "not_empty": true, "title": "string" } ], "json_ld_base_iri": "string", "json_ld_iri": "string", "json_ld_relative_iri_delimiter": "string", "json_ld_term_name": "string" } }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 }` #### [](#tag/schemas/operation/SchemaImport)Import Credential Schema. Import a Credential Schema. This operation accepts a schema definition and checks if a published schema with this definition already exists. If it exists, the operation returns the published meta-schema resource. If not, it creates and publishes a new temporary schema, using the schema definition hash as its slug. ###### Authorizations: *ApiKey* ###### Request Body schema: application/jsonrequired | | | | ------------ | ------------------------------------------------------------------------------------------------------------------ | | annotations | objectThe annotations of the resource. | | datarequired | object (SchemaImportDataRequest)The schema for passing arguments for importing a CredentialSchema. | | labels | objectThe labels of the resource. | ##### Responses **201** The published Credential Schema. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **404** The schema represents an HTTP "Not Found" status code. **412** The schema represents an HTTP "Precondition Failed" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. post/schemas/import URL for header-protected customer communication. https://api.truvity.{zone}/schemas/import URL for cookie-protected customer communication. https://docs.truvity.com/api/schemas/import ##### Request samples * Payload * Go * Java * TypeScript Content type application/json Copy Expand all Collapse all `{ "annotations": { "property1": "string", "property2": "string" }, "data": { "schema": { "fields": [ { "kind": "BOOLEAN", "is_array": true, "json_ld_iri": "string", "json_ld_type": "string", "name": "string", "not_empty": true, "title": "string" } ], "json_ld_base_iri": "string", "json_ld_iri": "string", "json_ld_relative_iri_delimiter": "string", "json_ld_term_name": "string" }, "slug": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" } }` ##### Response samples * 201 * 400 * 401 * 403 * 404 * 412 * 429 * 500 * default Content type application/vnd.truvity.published-schema+json;version=1 Copy Expand all Collapse all `{ "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "digest_multibase": "string", "json_ld_vocab_digest_multibase": "string", "json_ld_vocab_url": "http://example.com", "json_schema_digest_multibase": "string", "json_schema_url": "http://example.com", "published_at": "2019-08-24T14:15:22Z", "schema": { "fields": [ { "kind": "BOOLEAN", "is_array": true, "json_ld_iri": "string", "json_ld_type": "string", "name": "string", "not_empty": true, "title": "string" } ], "json_ld_base_iri": "string", "json_ld_iri": "string", "json_ld_relative_iri_delimiter": "string", "json_ld_term_name": "string" }, "slug": "string", "url": "http://example.com", "vcdm_json_schema_digest_multibase": "string", "vcdm_json_schema_url": "http://example.com", "version": 1 }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 }` #### [](#tag/schemas/operation/SchemaSearch)Search for Schemas. Search for Schemas with extended filters capabilities. ###### Authorizations: *ApiKey* ###### Request Body schema: application/jsonrequired | | | | ------ | ------------------------------------------------------------------------------------------------------------- | | filter | Array of objects (SchemaFilter)<= 4 itemsThe filter to apply to the search. | | sort | Array of objects (SchemaSort)<= 4 itemsThe sort order to apply to the search. | ##### Responses **200** The search results of Schema. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **415** The schema represents an HTTP "Unsupported Media Type" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. post/schemas/search URL for header-protected customer communication. https://api.truvity.{zone}/schemas/search URL for cookie-protected customer communication. https://docs.truvity.com/api/schemas/search ##### Request samples * Payload * Go * Java * TypeScript Content type application/json Copy Expand all Collapse all `{ "filter": [ { "annotations": [ { "operator": "EQUAL", "key": "string", "value": "string" } ], "created_at": { "operator": "BETWEEN", "left": "2019-08-24T14:15:22Z", "right": "2019-08-24T14:15:22Z" }, "data": { "digest_multibase": { "operator": "EQUAL", "value": "string" } }, "deleted_at": { "operator": "BETWEEN", "left": "2019-08-24T14:15:22Z", "right": "2019-08-24T14:15:22Z" }, "etag": { "operator": "EQUAL", "value": "string" }, "id": { "operator": "EQUAL", "value": "a860a344-d7b2-406e-828e-8d442f23f344" }, "labels": [ { "operator": "EQUAL", "key": "string", "value": "string" } ], "modified_at": { "operator": "BETWEEN", "left": "2019-08-24T14:15:22Z", "right": "2019-08-24T14:15:22Z" }, "revision": { "operator": "EQUAL", "value": 1 } } ], "sort": [ { "field": "DATA_DIGEST_MULTIBASE", "order": "ASC" } ] }` ##### Response samples * 200 * 400 * 401 * 403 * 415 * 429 * 500 * default Content type application/json Copy Expand all Collapse all `{ "items": [ { "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "digest_multibase": "string", "schema": { "fields": [ { "kind": "BOOLEAN", "is_array": true, "json_ld_iri": "string", "json_ld_type": "string", "name": "string", "not_empty": true, "title": "string" } ], "json_ld_base_iri": "string", "json_ld_iri": "string", "json_ld_relative_iri_delimiter": "string", "json_ld_term_name": "string" } }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 } ] }` #### [](#tag/schemas/operation/SchemaDelete)Delete Schema. Delete Schema's resource. ###### Authorizations: *ApiKey* ###### path Parameters | | | | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | idrequired | string<uuid>The primary and unique identifier of the resource (inside tenant) according to [RFC 4122](https://www.rfc-editor.org/info/rfc4122). | ###### header Parameters | | | | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Idempotency-Key | string\[ 32 .. 256 ] characters\[a-zA-Z0-9-]{32,256}From [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **Idempotency-Key** is a free identifier created by the client to identify a request. It is used by the service to identify repeated request to ensure idempotent behavior by sending the same (or a similar) response without executing the request a second time.Clients should be careful as any subsequent requests with the same key may return the same response without further check. Thus, it is recommended to use a UUID version 4 (random) or any other random string with enough entropy to avoid collisions.Keys expire after 24 hours. Clients are responsible to stay within this limit, if they require idempotent behavior.See [API Guideline Rule #181](https://opensource.zalando.com/restful-api-guidelines/#230) for further details. | | If-Matchrequired | stringFrom [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **If-Match** header field is used to declare a list of identifiers that are required to match the current resource version identifier in at least one position as a pre-condition for executing the request on the server side. This behavior is used to validate and reject optimistic updates, by checking if the resource version a consumer has based his changes on is outdated on arrival of the change request to prevent lost updates.If the pre-condition fails the server will respond with status code **412** (Precondition Failed). See [RFC 9110 Section 13.1.1](https://tools.ietf.org/html/rfc9110#section-13.1.1) as well as \[API Guideline Rule #182]\[api-182] for further details.\[api-182]: . | ##### Responses **204** HTTP 204 - No content. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **404** The schema represents an HTTP "Not Found" status code. **405** The schema represents an HTTP "Method Not Allowed" status code. **412** The schema represents an HTTP "Precondition Failed" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. delete/schemas/{id} URL for header-protected customer communication. https://api.truvity.{zone}/schemas/{id} URL for cookie-protected customer communication. https://docs.truvity.com/api/schemas/{id} ##### Request samples * Go * Java * TypeScript Copy ##### Response samples * 400 * 401 * 403 * 404 * 405 * 412 * 429 * 500 * default Content type application/problem+json Example /bad-request/bad-request Copy Expand all Collapse all `{ "detail": "string", "errors": [ { "location": "string", "message": "string", "value": null } ], "instance": "http://example.com", "status": 100, "title": "string", "type": "/bad-request" }` #### [](#tag/schemas/operation/SchemaLatest)Get the latest version of Schema. Get the latest version of Schema. ###### Authorizations: *ApiKey* ###### path Parameters | | | | ---------- | ------------------------------------------------------------------- | | idrequired | string<uuid>The ID of the resource. | ###### header Parameters | | | | ------------- | ----------------------------------------------------- | | If-None-Match | stringThe ETag of the latest version of the resource. | ##### Responses **200** Response with the latest Schema. **304** HTTP 304 - Not modified. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **404** The schema represents an HTTP "Not Found" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. get/schemas/{id} URL for header-protected customer communication. https://api.truvity.{zone}/schemas/{id} URL for cookie-protected customer communication. https://docs.truvity.com/api/schemas/{id} ##### Request samples * Go * Java * TypeScript Copy ##### Response samples * 200 * 400 * 401 * 403 * 404 * 429 * 500 * default Content type application/vnd.truvity.schema+json;version=1 Copy Expand all Collapse all `{ "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "digest_multibase": "string", "schema": { "fields": [ { "kind": "BOOLEAN", "is_array": true, "json_ld_iri": "string", "json_ld_type": "string", "name": "string", "not_empty": true, "title": "string" } ], "json_ld_base_iri": "string", "json_ld_iri": "string", "json_ld_relative_iri_delimiter": "string", "json_ld_term_name": "string" } }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 }` #### [](#tag/schemas/operation/SchemaUpdate)Update Schema. Update Schema's resource. ###### Authorizations: *ApiKey* ###### path Parameters | | | | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | idrequired | string<uuid>The primary and unique identifier of the resource (inside tenant) according to [RFC 4122](https://www.rfc-editor.org/info/rfc4122). | ###### header Parameters | | | | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Idempotency-Key | string\[ 32 .. 256 ] characters\[a-zA-Z0-9-]{32,256}From [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **Idempotency-Key** is a free identifier created by the client to identify a request. It is used by the service to identify repeated request to ensure idempotent behavior by sending the same (or a similar) response without executing the request a second time.Clients should be careful as any subsequent requests with the same key may return the same response without further check. Thus, it is recommended to use a UUID version 4 (random) or any other random string with enough entropy to avoid collisions.Keys expire after 24 hours. Clients are responsible to stay within this limit, if they require idempotent behavior.See [API Guideline Rule #181](https://opensource.zalando.com/restful-api-guidelines/#230) for further details. | | If-Matchrequired | stringFrom [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **If-Match** header field is used to declare a list of identifiers that are required to match the current resource version identifier in at least one position as a pre-condition for executing the request on the server side. This behavior is used to validate and reject optimistic updates, by checking if the resource version a consumer has based his changes on is outdated on arrival of the change request to prevent lost updates.If the pre-condition fails the server will respond with status code **412** (Precondition Failed). See [RFC 9110 Section 13.1.1](https://tools.ietf.org/html/rfc9110#section-13.1.1) as well as \[API Guideline Rule #182]\[api-182] for further details.\[api-182]: . | ###### Request Body schema: application/jsonrequired | | | | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------ | | datarequired | object (CredentialSchemaUpdate)The data of the resource. | | schema required object (ClaimsSchemaOptional) A schema for a ClaimsSchemaOptional. fields Array of objects <= 32 items A list of claim definitions. json\_ld\_base\_iri string The base IRI of the JSON-LD context that will be used to resolve semantics of the child claims. json\_ld\_iri string Deprecated \[DEPRECATED] The IRI of the JSON-LD context that will be used to generate the vocabulary. json\_ld\_relative\_iri\_delimiter string The delimiter used to construct the IRI of a term based on the context base IRI and term name. If omitted, the default value of # will be used. json\_ld\_term\_name string The JSON-LD term name that will be used to define semantics of the structure. | | ##### Responses **200** Response with the updated Schema. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **404** The schema represents an HTTP "Not Found" status code. **405** The schema represents an HTTP "Method Not Allowed" status code. **412** The schema represents an HTTP "Precondition Failed" status code. **415** The schema represents an HTTP "Unsupported Media Type" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. patch/schemas/{id} URL for header-protected customer communication. https://api.truvity.{zone}/schemas/{id} URL for cookie-protected customer communication. https://docs.truvity.com/api/schemas/{id} ##### Request samples * Payload * Go * Java * TypeScript Content type application/json Copy Expand all Collapse all `{ "data": { "schema": { "fields": [ { "kind": "BOOLEAN", "is_array": true, "json_ld_iri": "string", "json_ld_type": "string", "name": "string", "not_empty": true, "title": "string" } ], "json_ld_base_iri": "string", "json_ld_iri": "string", "json_ld_relative_iri_delimiter": "string", "json_ld_term_name": "string" } } }` ##### Response samples * 200 * 400 * 401 * 403 * 404 * 405 * 412 * 415 * 429 * 500 * default Content type application/vnd.truvity.schema+json;version=1 Copy Expand all Collapse all `{ "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "digest_multibase": "string", "schema": { "fields": [ { "kind": "BOOLEAN", "is_array": true, "json_ld_iri": "string", "json_ld_type": "string", "name": "string", "not_empty": true, "title": "string" } ], "json_ld_base_iri": "string", "json_ld_iri": "string", "json_ld_relative_iri_delimiter": "string", "json_ld_term_name": "string" } }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 }` #### [](#tag/schemas/operation/SchemaUpdateAnnotations)Update annotations. Update annotations of Schema's resource. ###### Authorizations: *ApiKey* ###### path Parameters | | | | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | idrequired | string<uuid>The primary and unique identifier of the resource (inside tenant) according to [RFC 4122](https://www.rfc-editor.org/info/rfc4122). | ###### header Parameters | | | | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Idempotency-Key | string\[ 32 .. 256 ] characters\[a-zA-Z0-9-]{32,256}From [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **Idempotency-Key** is a free identifier created by the client to identify a request. It is used by the service to identify repeated request to ensure idempotent behavior by sending the same (or a similar) response without executing the request a second time.Clients should be careful as any subsequent requests with the same key may return the same response without further check. Thus, it is recommended to use a UUID version 4 (random) or any other random string with enough entropy to avoid collisions.Keys expire after 24 hours. Clients are responsible to stay within this limit, if they require idempotent behavior.See [API Guideline Rule #181](https://opensource.zalando.com/restful-api-guidelines/#230) for further details. | | If-Matchrequired | stringFrom [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **If-Match** header field is used to declare a list of identifiers that are required to match the current resource version identifier in at least one position as a pre-condition for executing the request on the server side. This behavior is used to validate and reject optimistic updates, by checking if the resource version a consumer has based his changes on is outdated on arrival of the change request to prevent lost updates.If the pre-condition fails the server will respond with status code **412** (Precondition Failed). See [RFC 9110 Section 13.1.1](https://tools.ietf.org/html/rfc9110#section-13.1.1) as well as \[API Guideline Rule #182]\[api-182] for further details.\[api-182]: . | ###### Request Body schema: application/jsonrequired | | | | ----------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------- | | annotationsrequired | objectThe annotations of the resource. | | property name\* additional property string <= 128 characters ^\[^\n]{0,128}$ Value of the resource annotation. | | ##### Responses **200** Response with the updated Schema. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **404** The schema represents an HTTP "Not Found" status code. **405** The schema represents an HTTP "Method Not Allowed" status code. **412** The schema represents an HTTP "Precondition Failed" status code. **415** The schema represents an HTTP "Unsupported Media Type" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. patch/schemas/{id}/annotations URL for header-protected customer communication. https://api.truvity.{zone}/schemas/{id}/annotations URL for cookie-protected customer communication. https://docs.truvity.com/api/schemas/{id}/annotations ##### Request samples * Payload * Go * Java * TypeScript Content type application/json Copy Expand all Collapse all `{ "annotations": { "property1": "string", "property2": "string" } }` ##### Response samples * 200 * 400 * 401 * 403 * 404 * 405 * 412 * 415 * 429 * 500 * default Content type application/vnd.truvity.schema+json;version=1 Copy Expand all Collapse all `{ "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "digest_multibase": "string", "schema": { "fields": [ { "kind": "BOOLEAN", "is_array": true, "json_ld_iri": "string", "json_ld_type": "string", "name": "string", "not_empty": true, "title": "string" } ], "json_ld_base_iri": "string", "json_ld_iri": "string", "json_ld_relative_iri_delimiter": "string", "json_ld_term_name": "string" } }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 }` #### [](#tag/schemas/operation/SchemaUpdateLabels)Update labels. Update labels of Schema's resource. ###### Authorizations: *ApiKey* ###### path Parameters | | | | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | idrequired | string<uuid>The primary and unique identifier of the resource (inside tenant) according to [RFC 4122](https://www.rfc-editor.org/info/rfc4122). | ###### header Parameters | | | | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Idempotency-Key | string\[ 32 .. 256 ] characters\[a-zA-Z0-9-]{32,256}From [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **Idempotency-Key** is a free identifier created by the client to identify a request. It is used by the service to identify repeated request to ensure idempotent behavior by sending the same (or a similar) response without executing the request a second time.Clients should be careful as any subsequent requests with the same key may return the same response without further check. Thus, it is recommended to use a UUID version 4 (random) or any other random string with enough entropy to avoid collisions.Keys expire after 24 hours. Clients are responsible to stay within this limit, if they require idempotent behavior.See [API Guideline Rule #181](https://opensource.zalando.com/restful-api-guidelines/#230) for further details. | | If-Matchrequired | stringFrom [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **If-Match** header field is used to declare a list of identifiers that are required to match the current resource version identifier in at least one position as a pre-condition for executing the request on the server side. This behavior is used to validate and reject optimistic updates, by checking if the resource version a consumer has based his changes on is outdated on arrival of the change request to prevent lost updates.If the pre-condition fails the server will respond with status code **412** (Precondition Failed). See [RFC 9110 Section 13.1.1](https://tools.ietf.org/html/rfc9110#section-13.1.1) as well as \[API Guideline Rule #182]\[api-182] for further details.\[api-182]: . | ###### Request Body schema: application/jsonrequired | | | | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------- | | labelsrequired | objectThe labels of the resource. | | property name\* additional property string <= 63 characters ^(?:\[a-zA-Z0-9]\(?:\[a-zA-Z0-9\\.\\-\_]{0,61}\[a-zA...Show pattern Value of the resource label. | | ##### Responses **200** Response with the updated Schema. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **404** The schema represents an HTTP "Not Found" status code. **405** The schema represents an HTTP "Method Not Allowed" status code. **412** The schema represents an HTTP "Precondition Failed" status code. **415** The schema represents an HTTP "Unsupported Media Type" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. patch/schemas/{id}/labels URL for header-protected customer communication. https://api.truvity.{zone}/schemas/{id}/labels URL for cookie-protected customer communication. https://docs.truvity.com/api/schemas/{id}/labels ##### Request samples * Payload * Go * Java * TypeScript Content type application/json Copy Expand all Collapse all `{ "labels": { "property1": "string", "property2": "string" } }` ##### Response samples * 200 * 400 * 401 * 403 * 404 * 405 * 412 * 415 * 429 * 500 * default Content type application/vnd.truvity.schema+json;version=1 Copy Expand all Collapse all `{ "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "digest_multibase": "string", "schema": { "fields": [ { "kind": "BOOLEAN", "is_array": true, "json_ld_iri": "string", "json_ld_type": "string", "name": "string", "not_empty": true, "title": "string" } ], "json_ld_base_iri": "string", "json_ld_iri": "string", "json_ld_relative_iri_delimiter": "string", "json_ld_term_name": "string" } }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 }` #### [](#tag/schemas/operation/SchemaPublish)Publish Credential Schema. Publish a Credential Schema. This operation publishes a Credential Schema, making it available for use. If no slug is provided, the schema will be published as a temporary schema using the schema definition hash as its slug. If version is not passed, a default version will be equal 1. ###### Authorizations: *ApiKey* ###### path Parameters | | | | ---------- | ------------------------------------------------------------------- | | idrequired | string<uuid>The ID of the resource. | ###### Request Body schema: application/jsonrequired | | | | ------- | -------------------------------------------------------------------------------------------------------------------------- | | slug | string\[ 1 .. 256 ] characters^(?:\[a-zA-Z]\[a-zA-Z0-9]\*)(?:-\[a-zA-Z0-9]+)\*$Slug of a CredentialSchema. | | version | integer<int64>\[ 1 .. 99999 ]The version of the resource. | ##### Responses **200** The published Credential Schema. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **404** The schema represents an HTTP "Not Found" status code. **412** The schema represents an HTTP "Precondition Failed" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. patch/schemas/{id}/publish URL for header-protected customer communication. https://api.truvity.{zone}/schemas/{id}/publish URL for cookie-protected customer communication. https://docs.truvity.com/api/schemas/{id}/publish ##### Request samples * Payload * Go * Java * TypeScript Content type application/json Copy `{ "slug": "string", "version": 1 }` ##### Response samples * 200 * 400 * 401 * 403 * 404 * 412 * 429 * 500 * default Content type application/vnd.truvity.published-schema+json;version=1 Copy Expand all Collapse all `{ "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "digest_multibase": "string", "json_ld_vocab_digest_multibase": "string", "json_ld_vocab_url": "http://example.com", "json_schema_digest_multibase": "string", "json_schema_url": "http://example.com", "published_at": "2019-08-24T14:15:22Z", "schema": { "fields": [ { "kind": "BOOLEAN", "is_array": true, "json_ld_iri": "string", "json_ld_type": "string", "name": "string", "not_empty": true, "title": "string" } ], "json_ld_base_iri": "string", "json_ld_iri": "string", "json_ld_relative_iri_delimiter": "string", "json_ld_term_name": "string" }, "slug": "string", "url": "http://example.com", "vcdm_json_schema_digest_multibase": "string", "vcdm_json_schema_url": "http://example.com", "version": 1 }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 }` #### [](#tag/schemas/operation/SchemaRestore)Restore Schema. Restore Schema's resource. ###### Authorizations: *ApiKey* ###### path Parameters | | | | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | idrequired | string<uuid>The primary and unique identifier of the resource (inside tenant) according to [RFC 4122](https://www.rfc-editor.org/info/rfc4122). | ###### header Parameters | | | | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Idempotency-Key | string\[ 32 .. 256 ] characters\[a-zA-Z0-9-]{32,256}From [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **Idempotency-Key** is a free identifier created by the client to identify a request. It is used by the service to identify repeated request to ensure idempotent behavior by sending the same (or a similar) response without executing the request a second time.Clients should be careful as any subsequent requests with the same key may return the same response without further check. Thus, it is recommended to use a UUID version 4 (random) or any other random string with enough entropy to avoid collisions.Keys expire after 24 hours. Clients are responsible to stay within this limit, if they require idempotent behavior.See [API Guideline Rule #181](https://opensource.zalando.com/restful-api-guidelines/#230) for further details. | | If-Matchrequired | stringFrom [Zalando RESTful API Guidelines - models/headers-1.0.0.yaml](https://opensource.zalando.com/restful-api-guidelines/models/headers-1.0.0.yaml). The **If-Match** header field is used to declare a list of identifiers that are required to match the current resource version identifier in at least one position as a pre-condition for executing the request on the server side. This behavior is used to validate and reject optimistic updates, by checking if the resource version a consumer has based his changes on is outdated on arrival of the change request to prevent lost updates.If the pre-condition fails the server will respond with status code **412** (Precondition Failed). See [RFC 9110 Section 13.1.1](https://tools.ietf.org/html/rfc9110#section-13.1.1) as well as \[API Guideline Rule #182]\[api-182] for further details.\[api-182]: . | ##### Responses **200** Response with the restored Schema. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **404** The schema represents an HTTP "Not Found" status code. **405** The schema represents an HTTP "Method Not Allowed" status code. **412** The schema represents an HTTP "Precondition Failed" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. post/schemas/{id}/restore URL for header-protected customer communication. https://api.truvity.{zone}/schemas/{id}/restore URL for cookie-protected customer communication. https://docs.truvity.com/api/schemas/{id}/restore ##### Request samples * Go * Java * TypeScript Copy ##### Response samples * 200 * 400 * 401 * 403 * 404 * 405 * 412 * 429 * 500 * default Content type application/vnd.truvity.schema+json;version=1 Copy Expand all Collapse all `{ "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "digest_multibase": "string", "schema": { "fields": [ { "kind": "BOOLEAN", "is_array": true, "json_ld_iri": "string", "json_ld_type": "string", "name": "string", "not_empty": true, "title": "string" } ], "json_ld_base_iri": "string", "json_ld_iri": "string", "json_ld_relative_iri_delimiter": "string", "json_ld_term_name": "string" } }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 }` #### [](#tag/schemas/operation/SchemaHistory)Read Schema's history. History of the Schema's resources. ###### Authorizations: *ApiKey* ###### path Parameters | | | | ---------- | ------------------------------------------------------------------- | | idrequired | string<uuid>The ID of the resource. | ###### header Parameters | | | | ------------- | ----------------------------------------------------- | | If-None-Match | stringThe ETag of the latest version of the resource. | ##### Responses **200** Response with the history of Schema. **304** HTTP 304 - Not modified. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **404** The schema represents an HTTP "Not Found" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. get/schemas/{id}/revisions URL for header-protected customer communication. https://api.truvity.{zone}/schemas/{id}/revisions URL for cookie-protected customer communication. https://docs.truvity.com/api/schemas/{id}/revisions ##### Request samples * Go * Java * TypeScript Copy ##### Response samples * 200 * 400 * 401 * 403 * 404 * 429 * 500 * default Content type application/json Copy Expand all Collapse all `{ "items": [ { "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "digest_multibase": "string", "schema": { "fields": [ { "kind": "BOOLEAN", "is_array": true, "json_ld_iri": "string", "json_ld_type": "string", "name": "string", "not_empty": true, "title": "string" } ], "json_ld_base_iri": "string", "json_ld_iri": "string", "json_ld_relative_iri_delimiter": "string", "json_ld_term_name": "string" } }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 } ] }` #### [](#tag/schemas/operation/SchemaRevision)Read the specific version of the Schema. Read the specific version of the Schema's resource. ###### Authorizations: *ApiKey* ###### path Parameters | | | | ---------------- | ----------------------------------------------------------------------------------------------------------- | | idrequired | string<uuid>The ID of the resource. | | revisionrequired | integer<int32>\[ 1 .. 999999 ]The revision of the resource. | ###### header Parameters | | | | ------------- | ----------------------------------------------------- | | If-None-Match | stringThe ETag of the latest version of the resource. | ##### Responses **200** The requested revision of the Schema. **304** HTTP 304 - Not modified. **400** The schema represents an HTTP "Bad Request" status code. **401** The schema represents an HTTP "Unauthorized" status code. **403** The schema represents an HTTP "Forbidden" status code. **404** The schema represents an HTTP "Not Found" status code. **429** The schema represents an HTTP "Too Many Requests" status code. **500** The schema represents an HTTP "Internal Server Error" status code. **default** The schema represents a default response. get/schemas/{id}/revisions/{revision} URL for header-protected customer communication. https://api.truvity.{zone}/schemas/{id}/revisions/{revision} URL for cookie-protected customer communication. https://docs.truvity.com/api/schemas/{id}/revisions/{revision} ##### Request samples * Go * Java * TypeScript Copy ##### Response samples * 200 * 400 * 401 * 403 * 404 * 429 * 500 * default Content type application/json Copy Expand all Collapse all `{ "annotations": { "property1": "string", "property2": "string" }, "created_at": "2019-08-24T14:15:22Z", "data": { "digest_multibase": "string", "schema": { "fields": [ { "kind": "BOOLEAN", "is_array": true, "json_ld_iri": "string", "json_ld_type": "string", "name": "string", "not_empty": true, "title": "string" } ], "json_ld_base_iri": "string", "json_ld_iri": "string", "json_ld_relative_iri_delimiter": "string", "json_ld_term_name": "string" } }, "deleted_at": "2019-08-24T14:15:22Z", "etag": "string", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": { "name": "string", "version": 1 }, "labels": { "property1": "string", "property2": "string" }, "modified_at": "2019-08-24T14:15:22Z", "revision": 1 }` --- ### Solved problems and key benefits #### Problems solved by Truvity[​](#problems-solved-by-truvity "Direct link to Problems solved by Truvity") Truvity uses Self-Sovereign Identity (SSI) technologies to solve several key challenges in the B2B space. By combining decentralized systems, cryptographic methods, and lifecycle management tools, the platform helps organizations manage identities and credentials securely and efficiently. ##### Establishing trust and authenticity[​](#establishing-trust-and-authenticity "Direct link to Establishing trust and authenticity") Truvity leverages [Decentralized Identifiers (DIDs)](/ssi/overview/core-concepts/decentralized-identifiers.md) to authenticate both individuals and organizations. This registry verifies the legitimacy of participants without relying on central authorities. ##### Ensuring credential integrity[​](#ensuring-credential-integrity "Direct link to Ensuring credential integrity") Truvity provides strong cryptography to protect credentials from tampering. With cryptographic services that support cryptosuites like `Ed25519Signature2020` and `EcdsaSecp256k1Signature2019`, the platform ensures the authenticity and integrity of credentials. ##### Regulatory compliance[​](#regulatory-compliance "Direct link to Regulatory compliance") Truvity’s **Data Validation Services** make it easy to create credential schemas that comply with regulatory frameworks. Using standards like **JSON Schema** and supporting verifiable credential formats such as the [W3C VC Data Model 2.0](https://www.w3.org/TR/vc-data-model-2.0), the platform helps organizations meet global and local regulations effortlessly. ##### Streamlining credential processes[​](#streamlining-credential-processes "Direct link to Streamlining credential processes") Truvity simplifies the issuance and verification of [verifiable credentials (VCs)](/ssi/overview/core-concepts/verifiable-credentials.md) and [verifiable presentations (VPs)](/ssi/overview/core-concepts/verifiable-presentations.md). With **Verifiable Credential Services**, organizations can link credentials, add supporting documents, and manage the entire credential lifecycle. The solution also supports advanced use cases, such as preparing and linking related VCs that are in a preliminary, unissued state (called drafts). Once all linked drafts are complete, Truvity automatically issues them together in a single operation, reducing manual effort and maintaining consistency across the credential set. ##### Handling credential evolution and interoperability[​](#handling-credential-evolution-and-interoperability "Direct link to Handling credential evolution and interoperability") Truvity’s **Schema Management Services** let you define, version, and publish reusable [credential schemas](/ssi/overview/core-concepts/credential-schemas.md). These schemas establish a consistent structure and shared meaning for credentials, enabling multiple parties to exchange and automatically process them without requiring direct collaboration between counterparties. With versioning and evolution support, organizations can adapt schemas to new regulations or business requirements while preserving the validity of previously issued credentials. ##### Securing credential exchanges[​](#securing-credential-exchanges "Direct link to Securing credential exchanges") Truvity ensures secure and privacy-preserving credential exchanges using **Credentials and Requests Exchange Services** powered by [DIDComm Messaging](/ssi/overview/core-concepts/didcomm-messaging.md). ##### Automating complex workflows[​](#automating-complex-workflows "Direct link to Automating complex workflows") Truvity allows businesses to automate processes workflows by providing easy integration options with APIs and SDKs, available in languages like Go, Java, Python, and TypeScript. ##### Supporting auditing and compliance[​](#supporting-auditing-and-compliance "Direct link to Supporting auditing and compliance") Truvity provides revision history tracking for [key resources](/ssi/overview/reference/rest-resources-operations.md). This feature allows businesses to review changes made to these important assets over time, supporting audit trails and helping meet certain compliance requirements. #### Benefits of Truvity[​](#benefits-of-truvity "Direct link to Benefits of Truvity") The Truvity Platform offers significant benefits for organizations managing digital identities and verifiable credentials. ##### Enhanced trust and security[​](#enhanced-trust-and-security "Direct link to Enhanced trust and security") With [decentralized identifiers](/ssi/overview/core-concepts/decentralized-identifiers.md), Truvity ensures that businesses can trust the identities of participants. Cryptosuites protect against fraud and impersonation, offering peace of mind when dealing with sensitive data. ##### Reusable and interoperable schemas[​](#reusable-and-interoperable-schemas "Direct link to Reusable and interoperable schemas") Define, version, and share [credential schemas](/ssi/overview/core-concepts/credential-schemas.md) that multiple parties can use without rebuilding integrations. This improves interoperability across ecosystems and ensures credentials remain verifiable even as schemas evolve. ##### Comprehensive credential management[​](#comprehensive-credential-management "Direct link to Comprehensive credential management") Truvity simplifies the entire credential lifecycle, from creation to verification. Organizations can manage credentials with confidence, knowing that their integrity is safeguarded by advanced cryptographic methods. ##### Regulatory compliance[​](#regulatory-compliance-1 "Direct link to Regulatory compliance") Truvity simplifies the alignment of credential schemas with technical standards (such as ISO/IEC 18013-5:2021) and regulations (like eIDAS 2.0, AML/KYC, and GDPR). This ensures that organizations can meet regulatory requirements with ease, reducing the risk of penalties and legal exposure. ##### Secure data exchange[​](#secure-data-exchange "Direct link to Secure data exchange") The platform uses trusted standards like [DIDComm Messaging](/ssi/overview/core-concepts/didcomm-messaging.md) to guarantee secure and privacy-focused exchanges of verifiable credentials. ##### Operational efficiency[​](#operational-efficiency "Direct link to Operational efficiency") Truvity’s APIs and SDKs streamline credential issuance and verification processes, eliminating time-consuming manual steps. With pre-built components and flexible integration options, businesses can deploy solutions faster and with fewer resources. ##### Cost savings and flexibility[​](#cost-savings-and-flexibility "Direct link to Cost savings and flexibility") By using Truvity’s pre-built SDKs and APIs, organizations save on development costs and time. Whether you need to integrate with existing systems or build custom solutions, Truvity offers the flexibility to meet various business needs without breaking the budget. ##### Improved compliance and transparency[​](#improved-compliance-and-transparency "Direct link to Improved compliance and transparency") The Truvity platform records all credential-related activities in immutable, append-only storage, ensuring transparency and accountability. This feature makes it easier to meet regulatory audit requirements and maintain a verifiable record of all interactions. --- ### Platform capabilities Truvity provides key features to improve the management and security of digital identities and credentials: ##### APIs and SDKs[​](#apis-and-sdks "Direct link to APIs and SDKs") Access comprehensive [APIs](/ssi/api-reference.md) and [SDKs](/ssi/sdk.md) to manage the full credential lifecycle and secure credential exchange between parties. ##### Credential schemas[​](#credential-schemas "Direct link to Credential schemas") Define, version, and publish reusable [credential schemas](/ssi/schemas.md) to ensure consistent, machine-readable structures for credentials across your organization and with external partners. Schemas maintain semantic meaning for older credentials while supporting new schema versions for evolving requirements. ##### User-defined types (UDTs)[​](#user-defined-types-udts "Direct link to User-defined types (UDTs)") Use language-specific [UDTs](/ssi/sdk/credential-lifecycle/define-credential-schema.md) to define credential claims in your app code. UDTs provide strong type safety, detect potential errors at compile time, and simplify issuing and validating credentials directly through the SDK. ##### Labels and faceted search[​](#labels-and-faceted-search "Direct link to Labels and faceted search") [Attach labels and annotations](/ssi/sdk/manage-data/model-with-labels.md) to [REST resources](/ssi/overview/reference/rest-resources-operations.md) to improve searchability. Use the [faceted search capability](/ssi/sdk/manage-data/use-faceted-search.md) to efficiently filter and retrieve relevant results. ##### Linking files to credentials[​](#linking-files-to-credentials "Direct link to Linking files to credentials") [Link binary files](/ssi/sdk/linked-data/link-files.md) to credentials to support richer data representations. ##### Linking credentials to each other[​](#linking-credentials-to-each-other "Direct link to Linking credentials to each other") Create hierarchical relationships between drafts and credentials by [linking them](/ssi/sdk/linked-data/link-credentials.md). This capability includes the ability to link credentials that are in a preliminary, unissued state (called drafts). When you issue one draft in a linked set, the system automatically issues all linked drafts. ##### UI widgets *(Coming Soon)*[​](#ui-widgets-coming-soon "Direct link to ui-widgets-coming-soon") Use pre-built UI widgets, like the Forms widget, to display drafts, credentials, their claims and metadata directly within your app's interface. ##### History[​](#history "Direct link to History") [Track the history](/ssi/sdk/manage-data/view-credential-history.md) of [REST resources](/ssi/overview/reference/rest-resources-operations.md) to maintain audit logs and ensure transparency. --- ### Credential schemas A **credential schema** defines the structure and meaning of information in a [verifiable credential](/ssi/overview/core-concepts/verifiable-credentials.md). It acts as a **blueprint** that helps issuers, holders, and verifiers understand what data a credential contains and how to interpret it. #### What is a credential schema?[​](#what-is-a-credential-schema "Direct link to What is a credential schema?") A credential schema: * **Defines available information** Lists the claims (pieces of information) that a credential must include. * **Specifies the shape of information** Sets the type of each claim (for example, text, numbers, or dates). * **Enforces validation rules** Defines mandatory and optional claims, as well as allowed values (for example, if the age must be positive). For example, a “Dutch Driving License (Issued From November 14, 2014)” schema defines claims like `firstName`, `lastName`, `licenseNumber`, and `expiryDate`. Every issued driving license credential follows this same structure. #### Semantics and meaning[​](#semantics-and-meaning "Direct link to Semantics and meaning") Schemas organize data but don’t always explain what the data means. **Semantics** add this context and make sure everyone interprets claims the same way. Without semantics, identical claim names can have different meanings: * `status` might mean *employment status* in one credential. * `status` might mean *document approval status* in another. Semantic definitions remove this ambiguity. Systems can then process credentials consistently and accurately. #### Why schemas and semantics matter[​](#why-schemas-and-semantics-matter "Direct link to Why schemas and semantics matter") Reusable schemas and semantics enable rapid adoption of credentials by: 1. **Ensuring consistency** Credentials of the same type always follow the same rules. 2. **Enabling automation** Software can validate and interpret claims without manual checks. 3. **Supporting interoperability** Organizations can exchange credentials across platforms and maintain a shared understanding of the data. #### Truvity’s approach[​](#truvitys-approach "Direct link to Truvity’s approach") Truvity provides a **unified schema model** that defines both structure and meaning in one place. With this model, you: * Define a schema once and reuse it across ecosystems. * Stay compatible with multiple credential standards and formats. * Reduce complexity when developing credential-based solutions. #### Schema evolution[​](#schema-evolution "Direct link to Schema evolution") Data requirements and regulations change over time, and credential schemas need to evolve without breaking trust. To do so: * **Keep schemas immutable** Once a schema issues credentials, it never changes. * **Create new versions** Introduce updated schemas for new credentials. * **Maintain backward compatibility** Keep older credentials valid and verifiable. This approach ensures you can adapt to new requirements while preserving the reliability of existing credentials. #### Further reading[​](#further-reading "Direct link to Further reading") * Learn more about [verifiable credentials](/ssi/overview/core-concepts/verifiable-credentials.md). * Learn how to [work with credential schemas](/ssi/schemas.md). --- ### Decentralized identifiers (DIDs) In the self-sovereign identity (SSI) ecosystem, entities like issuers, holders, and verifiers need unique identifiers to facilitate secure interactions. Decentralized Identifiers (DIDs) provide this capability. #### What are DIDs?[​](#what-are-dids "Direct link to What are DIDs?") Decentralized Identifiers (DIDs) are a new type of identifier designed for the digital world. Unlike traditional identifiers managed by centralized authorities, DIDs are self-sovereign and universally unique, allowing individuals, organizations, or devices to be identified securely. DIDs enable verifiable interactions by allowing entities to prove their identity without disclosing unnecessary personal information. This approach enhances user control over digital identities, promotes privacy, and facilitates trust-based interactions across different platforms and services. For a deeper dive, see the [Decentralized Identifiers](https://www.truvity.com/ssi-essentials/what-are-decentralized-identifiers) article. Supported DID methods The Truvity platform supports a number of DID methods. To learn more about available DID methods, refer to the [Supported DID methods](/ssi/overview/reference/did-methods.md) page. --- ### DIDComm messaging DIDComm Messaging is a core component of the self-sovereign identity (SSI) ecosystem. It is a secure messaging protocol that facilitates information exchange between identity holders and verifiers. When an identity holder possesses a [verifiable credential](/ssi/overview/core-concepts/verifiable-credentials.md) in their digital wallet, they may need to share it with a verifier to complete a transaction or agreement. DIDComm Messaging allows for selective disclosure, ensuring that only the necessary information is shared, thereby maintaining privacy and minimizing data exposure. DIDComm Messaging establishes secure communication by enabling identity holders to resolve the [Decentralized Identifier (DID)](/ssi/overview/core-concepts/decentralized-identifiers.md) of the verifier and set up a trusted channel for information exchange. This ensures confidentiality, integrity, and authenticity throughout the communication process. #### Key benefits of DIDComm messaging[​](#key-benefits-of-didcomm-messaging "Direct link to Key benefits of DIDComm messaging") * **Enhanced Security**: Ensures that all communication is encrypted, preserving the confidentiality and integrity of the exchanged data. * **Privacy-Preserving**: Allows for selective disclosure, where only the necessary information is shared, minimizing the exposure of personal data. * **Interoperability**: Supports a range of SSI solutions and can operate across different platforms and services. * **Decentralized Trust**: Removes the need for a central authority, allowing direct peer-to-peer communication between parties. #### Use cases for DIDComm messaging[​](#use-cases-for-didcomm-messaging "Direct link to Use cases for DIDComm messaging") 1. **Credential Verification**: An identity holder can securely share a verifiable credential with a verifier, such as proving age for purchasing restricted goods without revealing additional personal information. 2. **Secure Communication**: Organizations can use DIDComm Messaging to establish trusted channels for secure communication, such as in financial transactions, healthcare data exchanges, or any scenario requiring verified digital identity. #### Further reading[​](#further-reading "Direct link to Further reading") * For more details on DIDComm Messaging, see the [DIDComm Messaging Specification](https://identity.foundation/didcomm-messaging/spec/). * To understand how DIDs work, refer to the [Decentralized Identifiers](/ssi/overview/core-concepts/decentralized-identifiers.md) page. * Explore [Supported DID methods](/ssi/overview/reference/did-methods.md). --- ### Digital wallets A **digital wallet** is a secure, user-controlled app that plays a vital role in the Self-Sovereign Identity (SSI) ecosystem. It serves as a repository for digital identities, enabling users to store, manage, and share their [verifiable credentials](/ssi/overview/core-concepts/verifiable-credentials.md) securely while maintaining control over their personal data and privacy. #### What is a digital wallet?[​](#what-is-a-digital-wallet "Direct link to What is a digital wallet?") A digital wallet in the context of SSI is more than just a storage solution. It provides a range of functionalities that allow users to: * Manage multiple [Decentralized Identifiers (DIDs)](/ssi/overview/core-concepts/decentralized-identifiers.md). * Create [Verifiable Presentations](/ssi/overview/core-concepts/verifiable-presentations.md) to selectively share information. * Control access to personal data through configurable privacy settings. #### Key features[​](#key-features "Direct link to Key features") 1. **Secure credential storage** Digital wallets offer a safe environment for storing digital credentials, such as IDs, certificates, and other personal documents, ensuring their protection from unauthorized access. 2. **Verifiable presentations** Allows users to create presentations of their credentials, enabling them to selectively disclose specific information to verifiers without revealing more than necessary. 3. **Privacy and consent management** Empowers users to control who can access their data and under what conditions, supporting privacy-by-design principles and compliance with data protection laws. 4. **Interoperability** Supports various identity standards and protocols, enabling seamless interactions across different platforms, services, and ecosystems. #### Benefits of digital wallets[​](#benefits-of-digital-wallets "Direct link to Benefits of digital wallets") * **Enhanced privacy** Shares only the necessary information and minimizes data exposure. * **User control** Grants users full control over their digital interactions, reducing reliance on third-party intermediaries. * **Security** Employs encryption, biometrics, and multi-factor authentication to safeguard credentials and sensitive data. * **Improved trust** Facilitates trusted peer-to-peer communication, enhancing trust in digital transactions. #### Use cases[​](#use-cases "Direct link to Use cases") ##### 1. Digital identity verification[​](#1-digital-identity-verification "Direct link to 1. Digital identity verification") Digital wallets allow users to store credentials like driver’s licenses, passports, or diplomas and share them selectively with verifiers for digital identity verification, ensuring minimal data exposure. ##### 2. Access management[​](#2-access-management "Direct link to 2. Access management") Users can use their digital wallets to authenticate themselves to access secure online services, physical premises, or restricted resources without revealing unnecessary personal information. ##### 3. Consent and data sharing[​](#3-consent-and-data-sharing "Direct link to 3. Consent and data sharing") Manage consents for data sharing with various service providers, ensuring user control and compliance with privacy regulations, such as GDPR. #### How digital wallets work[​](#how-digital-wallets-work "Direct link to How digital wallets work") 1. **Identity creation and management** Users create and manage DIDs and associated credentials within their wallets. 2. **Credential issuance and storage** Trusted entities (issuers) issue credentials to users and store them securely in the users’ digital wallets. 3. **Secure sharing** Users generate verifiable presentations to share specific credentials with verifiers securely. 4. **Consent management** Users set privacy preferences and control the conditions for sharing their credentials. #### Further reading[​](#further-reading "Direct link to Further reading") * Explore [verifiable credentials](/ssi/overview/core-concepts/verifiable-credentials.md) to understand their role in SSI. * Learn about [verifiable presentations](/ssi/overview/core-concepts/verifiable-presentations.md) and how they enable privacy-preserving data sharing. * Discover more about [DID methods](/ssi/overview/reference/did-methods.md) and how digital wallets implement them. --- ### Self-sovereign Identity (SSI) and the Triangle of Trust Trust in everyday life relies on familiarity and understanding - what people know, measure, and perceive as true. But how can entities, such as individuals, organizations, or devices, establish trust without prior knowledge or direct interaction? In the physical world, trust often forms through a **Triangle of Trust** involving three key roles: **issuers**, **holders**, and **verifiers**. #### Understanding the Triangle of Trust[​](#understanding-the-triangle-of-trust "Direct link to Understanding the Triangle of Trust") The **Triangle of Trust** illustrates how different parties establish and verify trust between one another: * **Issuers**: Entities that create and issue credentials. These can be governments, organizations, or other trusted authorities. * **Holders**: Individuals or entities that receive and hold credentials. They use these credentials to prove their identity or claims. * **Verifiers**: Parties that request credentials to confirm the identity or claims of the holder, such as banks, employers, or service providers. ##### Real-world example: Traveling to another country[​](#real-world-example-traveling-to-another-country "Direct link to Real-world example: Traveling to another country") When you travel to another country, the Triangle of Trust comes into play: * **Issuers**: The government of your destination country issues official travel documents, such as visas or entry stamps, to verify your eligibility for entry. * **Holders**: You, the traveler, hold these credentials and present them to the immigration authorities to prove your identity and purpose. * **Verifiers**: Immigration officers and border control personnel act as verifiers, checking the validity of your credentials to determine if you meet the entry requirements. ![Truvity Airlines Travel](/assets/images/airlinestravel-8bb251936ade083b05dea7191993c26e.png) ##### The Triangle of Trust in the digital world[​](#the-triangle-of-trust-in-the-digital-world "Direct link to The Triangle of Trust in the digital world") In the digital world, these trust relationships become more complex. For instance, before booking a holiday home, renting a car, or planning a vacation, you must provide official documents to establish trust. This process often requires service providers to handle and protect your information securely, complying with local regulations, which can be both time-consuming and costly. #### How SSI simplifies the Triangle of Trust[​](#how-ssi-simplifies-the-triangle-of-trust "Direct link to How SSI simplifies the Triangle of Trust") **Self-Sovereign Identity (SSI)** transforms the Triangle of Trust by digitizing and streamlining trust-building processes. Here’s how: * **Identity assurance** Offers a secure digital identity solution that reduces errors, forgeries, and the risk of document theft. * **Privacy and security** Empowers you to control your personal data, sharing only what is necessary for verification and reducing the need for companies to store sensitive information. * **Efficiency and cost effectiveness** Enables instant, remote verification of identity, saving time and resources for both individuals and organizations. * **Compliance and accessibility** Ensures that data handling complies with privacy regulations and facilitates easy access to necessary documents. SSI establishes trust more rapidly in digital interactions, enhances privacy, reduces costs, and ensures regulatory compliance. ![SSI and the Triangle of Trust](/assets/images/triangle-of-trust-57345c7c52908f9a32b39d42d8da22f8.png) #### How the Truvity Platform enables the Triangle of Trust[​](#how-the-truvity-platform-enables-the-triangle-of-trust "Direct link to How the Truvity Platform enables the Triangle of Trust") The Truvity Platform applies the principles of SSI through core components such as [Decentralized Identifiers (DIDs)](/ssi/overview/core-concepts/decentralized-identifiers.md) and [verifiable credentials (VCs)](/ssi/overview/core-concepts/verifiable-credentials.md). Its APIs and SDKs support seamless integration, enabling the development of trust-based apps for any business. * **For developers**: Learn how to integrate Truvity services using the SDKs in the [Truvity SDK](/ssi/sdk.md) section. * **For business leaders**: Discover how leveraging trust with SSI can enhance customer relationships, improve security, and streamline operations in the [Platform overview](/ssi/overview/about-platform/benefits.md) page. --- ### Verifiable credentials (VCs) **Verifiable credentials (VCs)** are a foundational element of the Self-Sovereign Identity (SSI) ecosystem. They are digital, machine-readable documents that contain a set of claims made by an issuer, which are cryptographically verifiable to ensure their authenticity and integrity. #### What are verifiable credentials?[​](#what-are-verifiable-credentials "Direct link to What are verifiable credentials?") Verifiable credentials (VCs) are digital assertions made by an issuer about a subject, such as a person, organization, or device. These credentials are: * **Tamper-evident** Designed to show any alterations or tampering, ensuring the data remains trustworthy. * **Cryptographically verifiable** Uses cryptographic proofs to verify the origin and integrity of the credential. According to the [W3C Verifiable Credentials Data Model](https://w3c.github.io/vc-data-model/): > A credential is a set of one or more claims made by the same entity. Credentials might also include an identifier and metadata to describe properties of the credential, such as the issuer, the validity date and time period, a representative image, verification material, status information, and so on. A verifiable credential is a set of tamper-evident claims and metadata that cryptographically prove who issued it. #### Key components of a verifiable credential[​](#key-components-of-a-verifiable-credential "Direct link to Key components of a verifiable credential") A typical verifiable credentials includes the following components: * **Claims** - statements about a subject (for example, name, age, qualification) that the issuer asserts to be true. * **Issuer information** - details about the entity that issued the credential, including its [decentralized identifier (DID)](/ssi/overview/core-concepts/decentralized-identifiers.md). * **Proof** - cryptographic proofs, such as digital signatures, that verify the authenticity and integrity of the credential. * **Schema reference** - a link or identifier that points to a public, machine-readable definition of the credential's claims. This ensures the structure, data types, and rules are consistently understood by all parties. * **Metadata** - additional data like expiration date, terms of use, and revocation status. Below is a simple representation of a verifiable credential structure: ![Verifiable Credential Structure](/assets/images/verifiable-credential-simple-e5857607599382e2e30294e35af82250.png) #### Verifiable credential lifecycle overview[​](#verifiable-credential-lifecycle-overview "Direct link to Verifiable credential lifecycle overview") The lifecycle of a verifiable credential involves several key stages: 1. **Issuance**: The issuer creates a credential containing specific claims and provides it to the holder, who manages and controls it in their [Digital wallet](/ssi/overview/core-concepts/digital-wallets.md). 2. **Presentation**: The holder presents their credential to a verifier, such as an employer or service provider, who needs to validate the claims. 3. **Verification**: The verifier checks the authenticity and integrity of the credential and its claims using cryptographic proofs and the issuer's public key. 4. **Revocation**: The issuer may revoke the credential if it becomes invalid (for example, a revoked license or expired certificate). 5. **Expiry**: The system treats the credential as invalid after it reaches its expiration date and blocks its verification. The following image visually represents the verifiable credential lifecycle: ![Verifiable Credential Lifecycle](/assets/images/verifiable-credential-lifecycle-20de2300018e2299ed4139afb643c58b.png) #### Benefits of verifiable credentials[​](#benefits-of-verifiable-credentials "Direct link to Benefits of verifiable credentials") * **Increased trust** Provides cryptographic proof of the credential's authenticity, reducing fraud and ensuring trust between parties. * **Enhanced privacy** Enables selective disclosure by sharing only necessary claims and protecting user privacy. * **Interoperability** Supports multiple digital identity systems and protocols, enabling seamless interactions across different platforms. * **Efficiency** Streamlines verification processes by eliminating the need for paper-based documents and manual checks. #### Further reading[​](#further-reading "Direct link to Further reading") * Dive deeper into the concept of [verifiable credentials](https://www.truvity.com/ssi-essentials/verifiable-credentials-in-decentralized-identity-models) and their role in decentralized identity models. * Explore how [digital wallets](/ssi/overview/core-concepts/digital-wallets.md) store and manage verifiable credentials. --- ### Verifiable presentations (VPs) **Verifiable presentations (VPs)** provide a secure and flexible way to share verifiable credentials (VCs) with a verifier while preserving the integrity and authorship of the data. #### What are verifiable presentations?[​](#what-are-verifiable-presentations "Direct link to What are verifiable presentations?") Verifiable Presentations (VPs) are machine-readable digital containers that package one or more verifiable credentials (VCs). They ensure that the information within is verifiable by cryptographic proofs, allowing the verifier to trust the origin and integrity of the presented data. According to the [W3C Verifiable Credentials Data Model](https://w3c.github.io/vc-data-model/) a verifiable presentation is: > A tamper-evident presentation of information encoded in such a way that authorship of the data can be trusted after a process of cryptographic verification. Certain types of verifiable presentations might contain data that is synthesized from, but does not contain, the original verifiable credentials (for example, zero-knowledge proofs). #### Key features of verifiable presentations[​](#key-features-of-verifiable-presentations "Direct link to Key features of verifiable presentations") * **Secure sharing**: VPs enable secure sharing of credentials between holders and verifiers, ensuring disclosure only of the necessary information. * **Selective disclosure**: Holders can choose which parts of their credentials to share, protecting their privacy by revealing only the required information. * **Cryptographic proofs**: Applies cryptographic signatures to prove the authenticity and integrity of the presented credentials and confirm they remain not tampered. * **Interoperability**: Compatible with various digital identity systems and protocols, enabling seamless interactions across different platforms. #### Example of a verifiable presentation structure[​](#example-of-a-verifiable-presentation-structure "Direct link to Example of a verifiable presentation structure") Below is a simplified illustration of a Verifiable Presentation's structure: ![Verifiable Presentation Structure](/assets/images/verifiable-presentation-simple-b69f5694395d710d267307ae612f6eb1.png) #### How verifiable presentations work[​](#how-verifiable-presentations-work "Direct link to How verifiable presentations work") 1. **Credential packaging**: The holder selects one or more verifiable credentials (VCs) stored in their [digital wallet](/ssi/overview/core-concepts/digital-wallets.md) to include in the presentation. 2. **Selective disclosure**: The holder decides which specific data or claims within the VCs to disclose, based on the request from a verifier. This allows for minimal exposure of personal information. 3. **Proof Creation**: The VP is digitally signed by the holder, creating a cryptographic proof that verifies the authorship and integrity of the credentials within the presentation. 4. **Presentation to Verifier**: The holder submits the VP to the verifier, who uses the cryptographic proofs to validate the authenticity and integrity of data. #### Benefits of using verifiable presentations[​](#benefits-of-using-verifiable-presentations "Direct link to Benefits of using verifiable presentations") * **Enhanced Privacy**: Allows users to share only necessary information, minimizing data exposure and protecting personal privacy. * **Increased Trust**: Provides cryptographic evidence of the integrity and authenticity of data, ensuring reliable and trusted digital interactions. * **Flexibility**: Supports multiple credentials in a single presentation, making it versatile for various use cases. * **Streamlined Verification**: Simplifies the verification process for organizations by providing a standardized and interoperable way to validate credentials. #### Further reading[​](#further-reading "Direct link to Further reading") * Understand verifiable credentials and their role in SSI [verifiable credentials](/ssi/overview/core-concepts/verifiable-credentials.md). * Learn how to [issue a verifiable presentation](/ssi/sdk/credential-lifecycle/share-credential-and-presentation.md) using Truvity SDK. --- ### Glossary #### Credential[​](#credential "Direct link to Credential") Same as [verifiable credential](#verifiable-credential-vc). *** #### Credential schema[​](#credential-schema "Direct link to Credential schema") A reusable, versioned definition that describes the structure, data types, and rules of information (claims) within a verifiable credential. Credential schemas ensure consistency and interoperability by defining how credentials are created, processed, and interpreted by different participants in a digital trust ecosystem. *** #### Cryptographic suite (cryptosuite)[​](#cryptographic-suite-cryptosuite "Direct link to Cryptographic suite (cryptosuite)") A set of cryptographic algorithms and protocols used to secure data and communications. In the context of verifiable credentials, cryptographic suites ensure the integrity, authenticity, and confidentiality of data. *** #### Decentralized identifier (DID)[​](#decentralized-identifier-did "Direct link to Decentralized identifier (DID)") A portable URL-based identifier associated with an entity. DIDs are commonly used in verifiable credentials to ensure they can be easily moved from one repository to another without needing to be reissued. Example: `did:example:123456abcdef`. *[Source: W3C Verifiable Credential Data Model](https://www.w3.org/TR/vc-data-model/)* *** #### DID method[​](#did-method "Direct link to DID method") Decentralized identifiers are not created and maintained in a single type of database or network like many other types of URIs. There is no authoritative centralized registry - or a hierarchy of federated registries like DNS - where all DIDs are written and read. Many different types of DIDs exist in today’s SSI community. They all support the same basic features, but they differ in how these features are implemented, for example how exactly a DID is created or where and how a DID’s associated DID document is stored and retrieved. These different types of DIDs are known as DID methods. The second part of the DID identifier format - between the first and second colons - is called the DID method name. Example of DIDs created using five different DID methods: * `did:sov:WRfXPg8dantKVubE3HX8pw` - Sovrin (`sov`). * `did:btcr:xz35-jzv2-qqs2-gwjt` - Bitcoin (`btcr`). * `did:v1:test:nym:3AEJTDMS×DDOpyUftiuoeZ2Bazp4Bswilce7FJGYbcUu` - Veres One (`v1`). * `did:ethr:OXE6Fe788d8ca214A080b0f6aC7F48480b2AEfa9a6` - Ethereum (`ethr`). * `did:jolo:1fb352353f51248C5104b407f9c04c3666627fcf5a167d693c9fc84675964e2` - Jolocom (`jolo`). *[Source: Self-Sovereign Identity: Decentralized digital identity and verifiable credentials](https://www.manning.com/books/self-sovereign-identity)* *** #### DIDComm messaging[​](#didcomm-messaging "Direct link to DIDComm messaging") A secure messaging protocol designed for exchanging verifiable credentials and other cryptographic data in a privacy-respecting manner. DIDComm ensures the secure and private communication between entities in the SSI ecosystem. *** #### Entity[​](#entity "Direct link to Entity") A person, organization, device, or other identifiable actor with a distinct and independent existence that performs one or more roles in the digital identity ecosystem. *[Source: W3C Verifiable Credential Data Model](https://www.w3.org/TR/vc-data-model/)* *** #### Holder[​](#holder "Direct link to Holder") An entity that possesses one or more verifiable credentials and generates presentations from them. Holders typically store their credentials in digital wallets or credential repositories. *[Source: W3C Verifiable Credential Data Model](https://www.w3.org/TR/vc-data-model/)* *** #### Issuer[​](#issuer "Direct link to Issuer") A role an entity can perform by asserting claims about one or more subjects, creating a verifiable credential from these claims, and transmitting the verifiable credential to a holder. *[Source: W3C Verifiable Credential Data Model](https://www.w3.org/TR/vc-data-model/)* *** #### JSON schema[​](#json-schema "Direct link to JSON schema") A declarative language used to annotate and validate JSON documents, ensuring that they conform to a specified structure. *[Source: Verifiable Credentials JSON Schema Specification](https://www.w3.org/TR/vc-json-schema/)* *** #### Meta-schema[​](#meta-schema "Direct link to Meta-schema") A universal, internal model in Truvity that captures the structure, semantics, and validation rules of a [credential schema](#credential-schema). The meta-schema allows different verifiable credential formats (such as the [W3C Verifiable Credential Data Model](https://www.w3.org/TR/vc-data-model/) or [SD-JWT](https://datatracker.ietf.org/doc/draft-ietf-oauth-sd-jwt-vc/)) to be expressed and derived from a single, unified definition. *** #### Relying Party[​](#relying-party "Direct link to Relying Party") Same as [verifier](#verifier). *** #### Schema publication[​](#schema-publication "Direct link to Schema publication") The process of making a [credential schema](#credential-schema) publicly accessible under a stable identifier (slug) and version. Once published, a schema is immutable and can be reused by multiple participants for credential issuance and verification. *** #### Schema versioning[​](#schema-versioning "Direct link to Schema versioning") The practice of maintaining multiple immutable versions of a [credential schema](#credential-schema) to support the evolution of credential definitions over time. Versioning ensures that previously issued credentials remain valid and interpretable even after schema updates. *** #### Self-sovereign identity (SSI)[​](#self-sovereign-identity-ssi "Direct link to Self-sovereign identity (SSI)") A new model for digital identity on the internet: for example, how people prove who they are to the websites, services, and apps with which people need to establish trusted relationships to access or protect private information. *[Source: Self-Sovereign Identity: Decentralized digital identity and verifiable credentials](https://www.manning.com/books/self-sovereign-identity)* *** #### Semantic definition[​](#semantic-definition "Direct link to Semantic definition") Description that specify the meaning of claims within a [credential schema](#credential-schema). Semantic definitions ensure that issuers, holders, and verifiers interpret data consistently, enabling interoperability and avoiding ambiguity in digital transactions. *** #### User-defined types (UDT)[​](#user-defined-types-udt "Direct link to User-defined types (UDT)") Custom data models created by users to define specific credential schemas. UDTs simplify credential lifecycle management by providing enhanced type safety and reducing the likelihood of errors during creation, issuance, and validation. *** #### Verifiable credential (VC)[​](#verifiable-credential-vc "Direct link to Verifiable credential (VC)") A tamper-evident credential containing a set of claims made by an issuer, which can be cryptographically verified to ensure authenticity and integrity. *[Source: W3C Verifiable Credential Data Model](https://www.w3.org/TR/vc-data-model/)* *** #### Verifiable credential JSON schema[​](#verifiable-credential-json-schema "Direct link to Verifiable credential JSON schema") A JSON Schema used for validating W3C Verifiable Credentials. The schema is contained within the verifiable credential itself. *[Source: Verifiable Credentials JSON Schema Specification](https://www.w3.org/TR/vc-json-schema/)* *** #### Verifiable presentation (VP)[​](#verifiable-presentation-vp "Direct link to Verifiable presentation (VP)") Data derived from one or more verifiable credentials, issued by one or more issuers, that is shared with a specific verifier. A verifiable presentation is a tamper-evident presentation encoded in such a way that authorship of the data can be trusted after a process of cryptographic verification. Certain types of verifiable presentations might contain data that is synthesized from, but do not contain, the original verifiable credentials (for example, zero-knowledge proofs). *[Source: W3C Verifiable Credential Data Model](https://www.w3.org/TR/vc-data-model/)* *** #### Verifier[​](#verifier "Direct link to Verifier") A role an entity performs by receiving one or more verifiable credentials, optionally inside a verifiable presentation for processing. Other specifications might refer to this concept as a Relying Party. *[Source: W3C Verifiable Credential Data Model](https://www.w3.org/TR/vc-data-model/)* *** #### Wallet[​](#wallet "Direct link to Wallet") A program or app that stores, manages, and protects access to holders' verifiable credentials. Digital wallets allow users to control their digital identities and selectively share information with verifiers. *[Source: W3C Verifiable Credential Data Model](https://www.w3.org/TR/vc-data-model/)* --- ### Cryptographic suites Cryptographic suites provide a set of algorithms and protocols for secure communication and data protection. The Truvity platform supports multiple cryptographic suites and key types to ensure robust security for digital credentials and transactions. #### Supported cryptographic suites[​](#supported-cryptographic-suites "Direct link to Supported cryptographic suites") | Cryptosuite / Signature | Supported Keys | Issue - did:key | Issue - did:web | Verify | | ---------------------------------- | -------------- | ----------------------- | ----------------------- | --------------- | | `ecdsa-rdfc-2019`, `ecdsa-sd-2023` | `P256`, `P384` | ✔️ | ✔️ | ✔️ | | `eddsa-rdfc-2022` | `ED25519` | ✔️ | ✔️ | ✔️ | | `Ed25519Signature2020` | `ED25519` | ❌ (Not planned) | ❌ (Not planned) | ✔️ | | `Ed25519Signature2018` | `ED25519` | ❌ (Not planned) | ❌ (Not planned) | ✔️ | | `EcdsaSecp256k1Signature2019` | `SECP256K1` | ❌ (Impossible) | ❌ (By request) | ❌ (By request) | | `RsaSignature2018` | `RSA-*` | ❌ (By request) | ❌ (By request) | ❌ (By request) | **Key notes:** * **`ecdsa-rdfc-2019` and `ecdsa-sd-2023`**: Support for P256 and P384 curves, suitable for both issuing and verifying credentials. * **`eddsa-rdfc-2022`**: Supports the ED25519 key, used for both issuing and verifying credentials. * **`Ed25519Signature2020` and `Ed25519Signature2018`**: Only supported for verification, with no plans to support issuance. * **`EcdsaSecp256k1Signature2019`**: Supports the SECP256K1 curve for verification. Issuance support is available upon request. * **`RsaSignature2018`**: Available by request for issuance and verification using RSA keys. #### Supported cryptographic keys[​](#supported-cryptographic-keys "Direct link to Supported cryptographic keys") | Truvity Key Type | JWX Type | JWX Curve | JWX KeySize | FIPS | SEC2 | OpenSSL | AWS KMS | | ---------------- | -------- | --------- | ----------- | ----------- | ----------- | ------------ | --------------- | | `ED25519` | `OKP` | `Ed25519` | | | | `ed25519` | | | `P256` | `EC` | `P-256` | | `P-256` | `secp256r1` | `prime256v1` | `ECC_NIST_P256` | | `P384` | `EC` | `P-384` | | `P-384` | `secp384r1` | `secp384r1` | `ECC_NIST_P384` | | `RSA2048` | `RSA` | | 2048 | `RSA-2048`? | `RSA-2048`? | `rsa 2048` | `RSA_2048` | | `RSA3072` | `RSA` | | 3072 | `RSA-3072`? | `RSA-3072`? | `rsa 3072` | `RSA_3072` | | `RSA4096` | `RSA` | | 4096 | | | `rsa 4096` | `RSA_4096` | #### Further reading[​](#further-reading "Direct link to Further reading") * Learn how to [issue a verifiable credential (VC)](/ssi/sdk/credential-lifecycle/issue-credential.md) and sign it with a cryptographic key using Truvity SDK. --- ### Supported DID methods Decentralized Identifiers (DIDs) are a foundational component of Self-Sovereign Identity (SSI) that enable secure and verifiable identification without relying on centralized authorities. The Truvity platform currently supports the following DID methods: * **did:web** The `did:web` method generates DIDs from web domains. This method is well-suited for scenarios where entities wish to leverage existing domain infrastructure to create decentralized identifiers. The `did:web` method provides a convenient way to integrate DIDs into existing web architectures. For more information, refer to the [did:web](https://w3c-ccg.github.io/did-method-web/) specification. * **did:key** DIDs using the `did:key` method are cryptographically derived from public keys. This method is suitable for use cases requiring lightweight, self-contained, and privacy-preserving identifiers. The `did:key` method is particularly useful when there is no need for an external hosting infrastructure. For more information, refer to the [did:key](https://w3c-ccg.github.io/did-method-key/) specification. --- ### Supported platforms and languages The Truvity platform supports several software development kits (SDKs) and UI components to facilitate integration with different environments and languages. #### SDKs[​](#sdks "Direct link to SDKs") Truvity offers SDKs in the following programming languages: * **[TypeScript](https://www.npmjs.com/package/@truvity/sdk)**: Comprehensive support for web and Node.js applications. * **[Java](https://mvnrepository.com/artifact/com.truvity/sdk)**: Suitable for backend development in enterprise environments. * **[Python](https://pypi.org/project/truvity_sdk/)**: Ideal for data science, machine learning, and backend scripting. * **Go (Coming soon)**: Optimized for building lightweight and efficient microservices. --- ### Resource permissions overview This table outlines the available actions for each REST resource and provides additional notes where relevant. | REST Resource | Create | Read | Update | Delete | Restore | Search | Other | Notes | | -------------------- | --------------- | --------- | ------ | ------ | ------- | ------ | --------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------- | | **api-keys** | ✓ | ✓ | ✓\* | ✓ | ✓ | ✓ | Read history, Read specific version | It's not allowed to read API key values | | **credentials** | ✓\*\* | ✓ | ✓\* | ✓ | ✓ | ✓ | Import, Upload, Verify, Download blob, Read history, Read specific version | - | | **desk** | - | - | - | - | - | - | Get DID-Document, Receive DIDCOMM Message | - | | **didcomm-messages** | ✓\*\*\* | ✓ | ✓\* | ✓ | ✓ | ✓ | Send, Read history, Read specific version | Can include verifiable credentials (VCs), verifiable presentations (VPs), and files | | **dids** | - | ✓\*\*\*\* | - | - | - | - | - | - | | **drafts** | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | Export, Issue, Read history, Read specific version | - | | **files** | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | Upload, Download blob, Read history, Read specific version | - | | **gdpr** | ✓\*\*\*\*\* | - | - | - | - | - | - | - | | **keys** | ✓\*\*\*\*\*\* | ✓ | ✓\* | ✓ | ✓ | ✓ | Generate, Import, Sign credential, Sign DIDCOMM Message, Sign presentation, Read history, Read specific version | It's not allowed to read key values | | **presentations** | ✓\*\*\*\*\*\*\* | ✓ | ✓\* | ✓ | ✓ | ✓ | Export, Import, Issue, Upload, Verify, Download blob, Read history, Read specific version | Contain verifiable credentials (VCs) | | **schemas** | ✓\*\*\*\*\*\*\* | ✓ | ✓\* | ✓ | ✓ | ✓ | Publish, Read history, Read specific version | - | *** **Notes:** * \* Only labels and annotations can be updated, not the underlying resource blobs. * \*\* Credentials are created by importing or from drafts. * \*\*\* DIDComm messages are created by the `send` operation. * \*\*\*\* Retrieves the tenant’s DID document (`did:web`). * \*\*\*\*\* Sends the GDRP support request to Truvity. * \*\*\*\*\*\* Keys are created by generation or importing. * \*\*\*\*\*\*\* Presentations are created by importing or issuing. --- ### Platform security You need to authenticate requests to interact with the Truvity SSI Platform securely. This page covers authentication and authorization considerations, and provides best practices to protect your keys. #### Authentication[​](#authentication "Direct link to Authentication") To authenticate your API requests, include an API key that you can retrieve from the [Admin Panel](https://admin.truvity.com). If you need to generate an API key, refer to the [Create API keys guide](/ssi/overview/security/create-api-keys.md). #### Authorization[​](#authorization "Direct link to Authorization") Currently, the Truvity platform does not support role-based access or authorization scopes. The API key itself grants full access to the system. #### Security considerations[​](#security-considerations "Direct link to Security considerations") API keys grant full access to your data, so it is critical to protect them carefully. If someone else obtains your API key, they can access and modify your wallet information. Here are some best practices to follow: * **Limit Access**: Only share API keys with trusted team members or systems. Keep them out of version control systems and avoid sharing them in public repositories. * **Frontend vs. Backend Usage**: It is okay to use API keys directly in frontend applications when building prototypes or in a secured environment. However, avoid exposing API keys on the frontend for public-facing applications. Anyone who can inspect the network traffic in a browser can extract the key and misuse it. * **Use an API Proxy**: For more secure applications, consider using an API proxy. An API proxy acts as an intermediary between your app and the Truvity Cloud API, adding authentication headers securely on the server side. This way, your API key remains hidden from public exposure. > **Best Practice**: Implement an API proxy when deploying your app to the public. The proxy handles requests from your app and forward them to the Truvity Cloud API, adding the necessary authentication headers on your behalf. By following these guidelines, you can ensure secure communication with the Truvity Cloud API while safeguarding your API keys from unauthorized access. --- ### Create API keys You can manage all your personal API keys in the [Admin Panel](https://admin.truvity.com), which becomes available after your account is set up. To get access, contact . #### Create an API key[​](#create-an-api-key "Direct link to Create an API key") To create a new API key, follow the steps below: 1. **Open the Admin Panel**
Go to the [main page of the Admin Panel](https://admin.truvity.com) and log in using your Truvity credentials. 2. **Initiate API key creation**
On the dashboard, click the `Create new API key` button to start the key creation process.
![Request API key creation](/assets/images/request-api-key-creation-ce520e15bfd3e031a46a20a4dceb006d.png) 3. **Provide key details**
In the API key creation form: * Enter a label that helps you easily identify this key (for example, "Production API Key" or "Development Key"). * Click the `Create` button.
![Create new API key](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAACDYAAAGgCAMAAABsEIVAAAACIlBMVEX////v7++lpaWDg4NoaGhOTk5jY2PHx8f8/Pzo6OidnZ3c3Nyjo6O/v7/e3t77+/vg4ODExMSrq6v39/f4+PigoKD+/v57e3sqKiohISFERETBwcGOjo5zc3OwsLAkJCRAQEC5ubl5eXnu7u5ubm4iIiK1tbXn5+fp6enDw8P9/f06Ojr09PSVlZWRkZGbm5uurq6oqKi4uLgxMTF2dnbNzc1bW1txcXFUVFRLS0uHh4dmZmY+Pj4oKCjX19fT09NRUVH29vZJSUnk5OQmJiby8vJ+fn7q6uqMjIxkZGSJiYm8vLw0NDQuLi7w8PCYmJj19fXJycnx8fHl5eWkpKTQ0NBsbGza2trz8/OysrL6+vpnZ2enp6c3Nzfm5ubV1dVgYGB8fHxYWFjZ2dlra2vt7e2BgYHs7OzGxsbPz8+xsbHi4uL5+fmvr69lZWW3t7fH2/N6qeNAidgeeNIYdtLn8PrA1/Okxe2Tuuldmd6yzvDE2vPq8vv9/f4ad9Ele9NEi9n7/P7j7frv9fz+/v/p8Pqgw+zs8/y81PJNkNvf6vmpyO5noOC30fFKj9p2qOMrftSGsuZ+reXy9/0xgdVYl901g9bR4faavutSk9z8/f4iedM7htfO4PWNt+jW5feQuOhxpuLK3vSXveqCsOb5+/1Hjdpjnd86hdf4+v31+f3c6PidweyuzO5to+GKtec9hdNsmtK0xNlYjcqYqr40fcurx8cZAAAeHklEQVR4AezBAQEAAAQAIOD/ZUNUAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwFAAAAAAAAAAAAAAAAFk9e+zcV0MTid/F8aOYNQYiIULMiSW0ASU0pRhZmi7NEul97bTt7//u+U3KMCQzCfvAv5/PZeq545uZYX5ounk7in+VOzHTDL/mmKclfrcV5xIx04YqyZi5h4r2jpi5mcK1ERERkbv30yzLPMC/yEOaR/B7TL9sZ0sUZV003ajSSdODil4apw/XRkRERLrS9PmhH1f15Km5g79lIEeTHgzPBpOJ/41sGKJrGNdGRERERhxeEGnFFY3SJPG3tLHoWXg2FLVcOhueOzS9EBERkWvTRtfYeMtEvGOSrqZ/RTa8YFG+JhteTrmafpyma2b2ktkwl6aZb4eIiIhcl1fTNK9/QtHzBZJO/J+fDYszLLlbnQ1LKHueo8m8ulQ2PMnR5JYhIiIi12aFZn4QZcM0b/752XCTZDZN8m1oNqB5gebdZbKhfZ4mPQsRERG5PjmaOCpa35MsRAEMJMwi8KFrqA9l0YnRoeRcOy5IzY2uDvXNraGkP5EYoVm1t0dRMdu32rG+gVDzJCdfkMwNBGeDlzjDl8mGXhrnHVzB458kzBrKNhOmFcBgcusGgoiIiMg2TSYFzy2abQA9NEOtOw7JAbgGV3N0ZfO78Kyt5FiUXtmDK8Nz/Sga2I+waPodgjXTJOM08fBsaKO5dYlsGKZrBJ7a8VP+qzh6HJJjB8BPaXJhGwFERETkLU0M5zrSZqSSDU2HdKVgEhlWpH9G2cRHesYmgrNh7Ud6ltpDZyxsRN+T3AnPhk80mcbZ0OfQjMMTMP4zzTRKRiuvHw78XJeIiIh8oYkjQA/NAotgZsfoM4Si7TR9ch+CsmEtQp9JBIh+JHkIfCW58CE0G7ZpvjTMhrkZmm8H8ASNz9B8R9ERzdNKRb1AABEREXlJMxuSDR4Ara9pplf6Og5p0scwA69p8l13Z5MfaXoBPE8mu2nGk8nkK5ivNOmT0eTXhbBGidP0Aes0LaHZcJNmqlE2nOZopnvgCRw/RDMM10GB5PsogESWdNYRQERERD7SLNbJhls3Z493K4fvvyx6f81PYB7QTEZh+tMkCwH/SbHukJxu9n7zv0yhxhHJ9D0glSMZCcuGjRzN4wbZcCdPU9iFJ3h8gt53tZ1/z3JsdRNBREREJEtyBuHZcB8lxcsOxnrO/8ovHAOIzZh3KPpKk6jNhiOaMxS10LxDtRsLlVMDUzTfg7Nhbp6mcKdBNhzRFYnC1B0/751GOaFZRz0iIiKSokmHZ8N8FCVtNMMoeUBzGxd10DyvyYa1Gd8FDfey3qf4tdDEvQsVmy5kQ+Sta2on4tDVhwbZYLytdcd3eGdEpknmUrgKERERZcMRyk5oJlBy6mWBzzOa/Zps6KIZQlmG5CNUi5Aci3oveB/1sqHGfVwyG7K/APXHn2bLQbNLM4XGREREdJLCiTbOhkOapqkyh+QKStZ+bjqaz71/nw7OhhjNramyaZJ5VJml+YqiYZqusGwYGzm4TDaM0XSuocH4LySzG8AqzRxERESkvhxNf+NsmGe1Xrj6pwr0+bUmG6ZY7SOqNPkuLUjQHAZmg/Px4R5Mw2w4mV3wng4b7818DOTdyEADIiIikqfZbpwN06z2BaY/R9bPhnFWm8E5737Wznh3SZpk9tiXDfkOV0t89x5cjbNhPIURuroajB+cIXlUukXkQzQgIiIiRzRdOLd8ZhI12RAh6RT83KfWXtK8bpn4racnVudoQ7rg8xEXdbFGLPi+DZfKhqMokPpGM/ak3niz4077fZRmFw2IiIhIjOak+m7Tz2qy4RHJ7BqqjNA8qntJZJImjjoOWeP1FbJhGWazQPMlFT7e+5T4UfELGxEREZFPDsnCGjx5mt9qsmGVpg1Vdkgu/F43G7ZpVhDuOMtac///bOiB6w+6OsLHuw7G3OopkBxCQyIiIpKnuYmKRJbkNGqy4R3NOKpMk3yJutkwSJM5aHC8ozfp+UqzdNVswBHNzG74eFc3ySxNAg2JiIjIPk1hHSUDeZru2my4MUbzFCUfJp95t6YeG4BrcZ5m//wzV1HyzX+4YaBpPIqLXtM0w3MjS3Ls96tmw42PNC8Pwseb2yyZxyWIiIjIDzQLo+0wc5M0H5drswFJmrFRuJo76cS89w4XXx2hKwnXBM03lDQvkMy+/R1mz96w0wq/OZoIfN7Q9F01G/CArqnw8WYgx6IYygY6IpnVexAREZFA/QW6spEXk50OTfYMAdmASboiSyPjGcd9VTOAGF35h2/nsyxaheuUrun7vbsww3RNj4+czC/QPIPfEs1IzfGPL1fLBu+TnbPQ8a4pupw78LdGEiIiIhLse44XDCEwGxI5+rXARPO8qAlF31gyAXMwSb+dVM1Vic4n+LxKk8zeuXI23MvQ5D6EjXfN0fUNFd1esoiIiEiQ5W88F7mN4GzA4FeHFWP7KOrPsGy6jyaCom3HywaT6kizIrtyAL8+mjwueEGzeuVswFyWZid0vCtz8YrQUa+bREREJNjEUZauQiSZQkg2mNuT7+maXjlFWetIgabQPYgMSecURRMZun5ByW870w7NWPdnXPSFZgsXxGkyV88GDNM1GjLee0n2/C3tOzPZP5chIiIidfx+9+mv68to6LTt17O78EttPvgrkUKVgUS87/Mazq398jg+e4B/qdrxOKk+KbH3f+zcYWtb9xXA4ePWsBurjbixfcdIwohi0kzU9sosNHygJnS2DYHZTkisySHBrAjWaOT7v5slLzQixXaorF41z3Pf/T/Bj3MOdyE+BgAw/Nt4HHEVAIBXo39C9eIKAAAno2FDNy4DALCyufHyH6MrzkZcBgDg2Z8ubMV1AACy4e8rcTUAQDb8ebAbAACXK/6yuv7oeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwMcAAAAAAAAAAAAAAAAAAACACgCYQ79JMrQBgDk043QYJUNRNAGAOVQUo3SYYTUUzXYVAMAcqtrNYmbdcB4N/SIAgLlV9M/DYUbVMCwCAJhjxXAm3VBVxbAfAMBc6w+LqprBsKG/HADAnFvut6sZrCiWVwIAmHMry0W7uvlhQ68Zn+LoqB2/7CxfxC97nqfxs+ZREQDAVDV7/ZvPhmK4UMUnaGee/MpseJqdAACmqloYFjefDcv7MeNsuJsvAgCYrv3lm86Gqt188nim2fBDRJlvIhYCAJiix0+a7er3lQ37OXjwIDtPB912zBkAkA1Ht35NNhRfb+4NDk/eZ0NjafDlF/sxVpQHrYPv/jmZDT+s/5gji/eeBQAwPbeO6p4ND7cz759mvrvIhvXFXMzsNuJcdZjZPc37JxPZENE/Ps2tznIAAJ9XNmzkwdtY+G8ufjPOhnz1unq+nX9sR8Sd3N6PlS+yVUxmQ6zmIDsBAHxe2XA02Hs9erufd8fZsBnnltfyOKKReSsimt0sJ7PhONd3u92H8ZkAANkwaSnvfHAS+SpXIx7kvRhZza8msuFJd20h/pAb8TsBALJht9Epf3ZJNvz70VeH662JbLg7KobD3PjXyGHem8iG+P44Ir57HR8orw0A6DR265UNjXLk6mzY/zJzrXW2NpENnTyLaOV7exfZcInyUwAAjTplw05Z3u5VVy8phnu59DgiVieyocztiL38aefCyUU2TAMAUPVul+VOfbKhUXZ617pt+D5bVXyUDT/lZsRhvov3ZMM0AUCvUzbqkg27ZdmLa2XD17k3fjv4fzY8iHPV2agY3uVZM0a+lQ1TBgC9stytSTY0yttxvWx4k9mJWFnKXB1nw+JORPw1144iVrZytR8Rj16+kA1TBgC3y0ZNsqFT9i7NhtbehTfRPsg8O1jM+7k9zobz7/As82mc23mZraXNrRw8kw1TBgC9slOTbCjL6tJseK8T0Vs9zWz9526ujbPh7Z21zK3jGNvf+DFza+lJyIYpA4CqLGuTDXF9/bfP4gPV44cfJMY3CwEA3IA5zAYAQDbUGQAgGwAA2QAAyAYAQDbUGQAgGwAA2QAAyAYAQDbUGQAgGwAA2QAAyAYAQDbUGQAgGwAA2QAAyAYAQDbUGQAgGwAA2QAAyAYAQDbUAgAgGwAA2QAAyIbZAwBkAwAgGwAA2QAAyIZRNQy/lQ3zBABkAwAgG6YPAJANAIBsAABkAwAgG2rjf+zbhVNjixmG8bdFLuu+mwe5qwcLsoIXzWKFpLj2pjjru///aMk5gZuDU2EC8/4gnnzzjeaJTUOlriYzMzNnQ8Pm5maLYnb3rlrQmR53bG7HB0VKe/7YUl7z5mbDNckGMzMzZ8PvQGJEBeYCoEpn+gq0xwftC2ryW3TC786Ga8TMzJwN3FaBas6XDR1AW2xQdj2nKwMklpwN15KZmTkbUvpTRfZ82fAxABLThYM6FfmtElLfr182mJmZORuG4YsOvIS+82RDC7yCh8dlg5qSMOVsMDMzu37ZUAptOrAOb86RDU976Z1O0HVsNmgFSs+fDY+XxmRmZnYVOBtuJwu+FPkxYLAlzIb2dLr7qUIL6XTX4akwrk64e2w2fIPeU7PhXmk6vVihnDubAaTXt7SnNZ3eUORmOt0jMzOz4uJseNICt5U3Dg8nwmxoTEK7QhNQrZioGBpg4thsWIbMadnQuAhly9pTMUqk752ku5D5rtAgfJaZmVlxcTZM3XhOSpGKLB8elYTZoB4oUagSlhQz0seg1JglWXFcNixA1ynZ8LQNKneU8wzSN9urep7Db1EsTCqnPiDbKDMzs+LibGhRKbQr9BJ2tRFlQz8kw31vQUpx8/AkKos7x2XDBjw7JRt2IfmvaDmoHAvPBGFoPNmf8lfYlZmZWZFxNkyoAdoUWocltUXZoBR80Z4pmFJcGc93orLYPpoNjfPwvP3kbBiH9C2FughmFOqEz9LOczKr+UUWZGZmVmScDSV62pv/UuS3gE2pM58NrVCSf27/qJglKFdOiuHXB4O6fuTcLkkB1ToxG1ohM6BQXUC3IrXQKqkcJiU1DdOrYmNmZuZs2JCm4In2jMOKtJ3PhrqApKSxgC7FlUCt8mVxc39Qgb6JihOz4X1A34wiK1CiyF3YiK6piSJiXMXGzMzM2dAm7QyTir4QmV6VyvPZoA74Iv0BtxVzL03msXLqn5OKZwNBtms3WuLYbMgkoPKxIq0UWpf0KEFmVXoDSyo2ZmZmzoZOSW+gXXoPPZLW97PhIZRI5Tz/pJj3kJqPJGFgf1DpWM5jRY7PhsgzRSYoVKY9bTCpexlSKkpmZmbOhhmokdYJ7hdmQ1MfSU0Ps664v1Noo3BQ5LRsCJoTsKLQFLQ9PDAZrgs1uaNmFSUzMzNngyrpm/0W0KHCbNAbWPgFDxUz9pxCHx5fJBuCd1qBzH3lvIQexTUmyayOwjcVJzMzM2fDTXgyDu/j2XAHejrpW1bMFEzM7nsDKxfJhkpJG1D2XXtuQYcO6YHJJIMqUmZmZs6Gf/RRmSVbEc+GijTJD5QqrhJuaV8DdFw0G753w2g4PwufFam7p1A/dMMTFSkzMzNng9oAxhXPBu0C1CqmHcp0oDFLMHfBbND9DPzSnhV4cV85A+mu/Oop4PmYipWZmZmz4QsQzB3OhgUg8Ugxr+CJ/tQDLRfNBtXuf72hAzKtX+re7yYYbldoCuiQmZlZ0XI2qBvKdTgb9OJIDQwl4j/I3ILepxfNBm1A2aqk14vkJX4pUhfAQ5mZmRUvZ8M8TB7Nhha4o5iHsK5C3fD5wtnwvQx2lbOSeg4k3tzXvk2GZ2VmZlYEnA0XUsOHCv2fra5V9Q/pwNMkf9NVY2Zm5mxYTrChS/YAVnTVmJmZORumoF2XbJ3MkK4WMzMzZ8Pj93106XK9boFxXSlmZmbOhl9dw/B8RpepujuA7F90pZiZmTkbbgLP3+lS/RP4MKCrxczMzNnQsNn1akmX6+Zgx8S/2bUDz0bSP47jTxek8mvS+c0YWHCCrCjcEQAVFUVZ3e6dxmChWNagaaft7Da9v/2Sa3o4ZA+SPA+v11/x9vl+BwEAUiIbAADZAABsIBuiBgDIBgBANgAAsgEAkA0AQMxkAwAgGwAA2QAAyAYAIGayAQCQDQCAbAAAZAMAEDPZAADIBgBANgAAsgEAiJhsAABkAwAgGwAA2RAzAEA2AACyAQCQDQCAbIgYACAbAADZAADIBgBANpQhYgBAGU02jLNZiBgAMMvGkWRDN+uFiAEAvawbSTZMM3NDzABglmXTSLIhdLPxLAAAkZqNs26IJRvCaZb1ZmUAAKJTznpZdhriyYbQzQCAaHVDTNkQpt1xBgBEaNydhgiyISUAgGwAAGQDACAbAADZAABEQDYAALIBAJANAIBsKEPiAIByB9nQWWZDHRIHABQfJtvPhurywyAkDgAY7CYbzo9D4gCA4/O8U4ZtKstOPx/0hgEASNqwd1BvORtCOeoX07PxeQAAEnY+PptVo61nQ6eafL1+3wsAQLK6Rzdf887Ws2E1N8yGpxdH11ejAAAkZ3R1fXRxOjxZjw1bnhv6xdXZ6dG3/7979TsAkID/rb379dvFH2fTulNuPxtWZ4pienjz6f3FL78BAKm5OPp0czir1yeK7XdDv7gcDI+71wBAcrrHhweTaifVsO6GKp/MplcAQDKmr2azy2I1NZQh7KgbluHQr6oaAEhG/02nM9pRNayUf4fDUh8ASMXoTbkUdqhcGgEACSnfhN0rAYCUBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADgX8poBQBAMWgHAEgxGkYREw4AEIV/kqETrdFKBOEAAKrhNRn6EXtNh/13AwCohlUzVFUdrapalcNeuwEAWEdDVddFkS9NopMvFUVdV+twCADA/qphFQ2387v7Jlr3d/PbVTj8l254eHxqY/f0+BASBIALxaoainkTvXmx6oaf3ike2zQ8hrQAwLoa8u9NAr7n624IG/xo2+fFS4jby+K5bX+E5ADgRFHV+bxJwZ/zvK5+cqZ4bJ8WIQWLJ3sDAAmODXVx2yTitqg3zw0PbbsIaVi07UNIBwCUo1G/qifzJhHzSV31R6Nyw9jwHFLxbG4AIL2xIT+5axJxd5Jvnhue2kVIxaJ9CgCQWDZMru6bRNxfTTZnQ9u+hFS8tG0AgKSyoSpOBk0yBidFtTkbQjpkAwDJvTbk0/MmGefTfPXcIBsAYE83isMmGYdvVwrZAAB7yYZhk4yhbACAfWbDxy9NMr58lA0AsMdsOPjcJOPzgWwAgP1lw2Va2XApGwBANsgGAJANG8iGNACAbJANACAbZAMAyAbZAACyQTYAQMxkg2wAANkgGwBANsgGAJANsgEAEsmGv9i7E6XEtQUKw+uRbVhh7gCSDgIGwUCYxHnGjq94C7JTbDTc+VDU6fUp8wv8tcd/T71R/5tkQ/O0hf+S98vxlA0iIqJs+KdyfhvwnLMOE057o1vtnTMRtC19GhfttjPgRrG9K0cO25bLw2RD6DdccjQOYOlGUXSC1CSKoimMWRSVkJgH4wVZ70yb2ChGlh6Aqyjy//RsEBERZcNFEwmvl+daE0hNZlyrwtKhsQRgeqCCXQ3yGpbhQbLhJqJR/oUUbkneITUhuegisa4bbLTGNHL3WJvS4gNYkA/Khj+ciIiy4RGA1w3uQwDTNBtCx3FCAKiNTDY8OalnJhoAMOGG76yFgOds5JJscFIHGW2Y1ElG5y+vJMc/YXhXJBehnQ0sf82GMEdyUD5/Jjn6lWbDVaqnbBAREWUDydwbcPpMclABvLLJhluSfO0BCEw2nPCrKdYa3LoF3pm6BuYHXdvQfCbrZwB++iRLMKpc6+1kAytfsuGS5K0HoDowUTEl87ApG0RERNkQAOGINEP3gZ0NZAFo7csG1wFWwMfRZENvO5tyQUYw7shncrabDaPWTjasXPIaG79JdpUNGURERNlQfwd8Jh6A9m42XACI9mTDC+C8ADX3WLKhvI2DE5IrbIQLcrIgV1Y2uOTFTjaUyEULG08LsqdsyCAiIsqGcwB9JmZBEIysbEh+fd6TDQHw4baB8yPJhtAli0i8x3F8j40eOUNMflrZcEny3s6GDhnD+IzjorIhg4iIKBuGAAa02dlQArx6djYMnoAOi0BwJNlwQ7KAb2akj4CM5ttsWJbJRtPKhoF5TSkbRERE2ZBhCoTclw2zd6DAJBtqvxM+E5dAlxwDzdHebPB+G9EBsqFK8gZfrUj3F54GZMHKhu6CLG2z4Y2k/z0b3B9GTdkgIiLKBpI94DQjGwrD4fDhzANaHZMNqTYTE6BEuqfA475s2GocIBsqJB189UmWAVyQsZUNeCAXK6TZUCNZ+ZYNW11lg4iI7KdsSE1emZ0NzyYGpsDNEWfDz4jsAaiS+ZaVDc1ncuwpG0RE5D+hbPCzJymMSZ5pNixfExE3Pkwu9AF09q5teDXyB8iGs6xJioLJhfmI9K1swL1L9tJsCEkWM9Y2OMZc2SAiIsoGkp8AFt+zIYjjOACaVySzlkTma0D1ce0d8I9iSeSEZBVfxGSuuNYhO3Y24JIctE02oE5ea0mkiIgoG/6F2JpCyN3e3lobMKN3oLInG85haeWPIRvaJHtINKcPDzcAWgtabuxsCEfkXZoNz+QdjN8PD2fKBhERUTZkGM2BWyZugdDdZgOngNfPzoYz2OJjyAZ0yDISS5ITAEXaHu1sQEAyb7JhSA7eTXHUyQ9lg4iIKBuyVAFnwTX3BijQyoZRCBQys2HUBIoXiRVQOIpsmJJcYeORHPw0JVFJxOSoaWcDXrg2TFuiaC2RUDZkERERZcPYA+4HJBc+gNjOBpYAjLOyYQjMR9b76BiyIYzI1xUABC75COAmHRcx74OdbDitk+QwTYhFkN693feUDSIiomzI5AMIC37gAOhxJxsGLWBisiFcpmbkDVCgEXnAZ3Y2eMvUQS7OPnPJxXj4o0Oy/2bmHpownsnznWzAdJsNzoB0+5eXZZesd82P7jjVS7Lhyv6sbPgDiYgoG9wPpM7qu9nATwAxySosL+wAuGDqBFhlZoPl4xDZgKBOo98F0ByRP5B6IN3aTjbM+0yzAascjVEhbYr9+01ulQ1/JhERZQNZLngA3pZl8ks21GtA1/2WDT7wNmDqB4DZUWQDupd1kvlGz0uXKZwgdUryYycbMHHJIRKth4gko+sQygYREVE2/BP1xvjK5V/pMNkAzE+X3Sb+K15tcvP+j/btQMONLY7j+LSwWWGmbSJQLoS0xr5DjYhFia7cSBqVoCoaAzRJRpP0mZqmfb/b0QvQLCDn8Pkw7/D1+59JLvK2AQDZ8EcE2RAB2RADAGSDbAAA2SAbAEA2yAYAkA2yAQAiIBtkAwDIBtkAALJBNgCAbJANABAA2SAbAEA2yAYAkA2yIRAAIBtkAwDIBtkAALJBNgCAbJANABBXNhRxZUMhGwDgitkwX0djLhsA4JrZMJx/WUfiy3z4WDYck1gcY8wGAGTD93Ukvj+WDbvqkMTiUO0SAIhGJ8+zWWv46rSOxOnVsDXL8ryT/MW22iex2FfbBIgKmBtmrcHtj3UkftwOWrMLY0OyqapDNGNDtUmAuIArRXv6uhnJ3HBqvp62L90o6rlhF0c3HHbGhggByIa7Zbo4ryNwXqTLu0eyIflaVfvDMQnb8bCvqq9JbADwuKEsuv2P41MEW8P4Y79blJeeNtS2VRy2SXwAMDe0Brfpm5uf51/f1sH69uv88+ZNejtoXR4bapvtrgrdbrtJogOAbMgb5bvuaDJ+2Xvx4elv/wbn6W8fXvRejiej7ruykdfZAABc51+K9nTZn4yfv+29X63+CdBq9b739vl40l9O27OGagCA6+j83w2fRuni88NNqB4ePi/S0ac/1SAbAOB6Z4q6G57cj56lzeYkSM1m+mx0/6SuhiufKABAN2RlMR12l/dBWtZfdzgtykw1AMDV7xR5lpXtorgLVlG0yyzLA7hQAIBuyBtZNgtYljVy1QAAIXRDJ681gpXXOqoBAEIIh1oesE5NNABACDoRSACAYMRWDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD8B8dpxFmMsMAWAAAAAElFTkSuQmCC) 4. **Copy the API key**
The form displays the created API key. **Copy it immediately**, as this is the only time the key is visible. caution For security reasons, the page shows the API key only once. If you forget or lose the key, you need to generate a new one. ![Created API key](/assets/images/created-api-key-358698679b076d203e5421922122f93a.png) #### API key expiration[​](#api-key-expiration "Direct link to API key expiration") info API keys expire after **30 days** from the date of creation. You receive email notifications **7 days**, **3 days**, and **1 day** before the key expires, so you have time to [rotate your key](/ssi/overview/security/manage-api-keys.md#rotate-an-api-key) without service interruption. #### Next steps[​](#next-steps "Direct link to Next steps") After copying your API key, you can start using it to authenticate your requests to the Truvity SSI Platform's APIs. Ensure that you store the key [securely](/ssi/overview/security.md#security-considerations) and only share it with authorized individuals or systems. #### Further reading[​](#further-reading "Direct link to Further reading") * [Manage API keys](/ssi/overview/security/manage-api-keys.md) --- ### Manage API keys You manage all personal API keys in the [Admin Panel](https://admin.truvity.com) after your account is set up. #### Revoke an existing API key[​](#revoke-an-existing-api-key "Direct link to Revoke an existing API key") To revoke an API key, follow the steps below: 1. **Open the Admin Panel**
Go to the [main page of the Admin Panel](https://admin.truvity.com) and log in using your Truvity credentials. 2. **Locate the API key**
In the list of available API keys, find the key you want to revoke. Click the corresponding `Delete` button to start the revocation process.
![Request API key revocation](/assets/images/request-api-key-deletion-928a6d3ee0e98f0b3b92d48c82210967.png) 3. **Confirm API key revocation**
A confirmation dialog appears. Review the information and click `Confirm` to revoke the API key. danger When you revoke an API key, all applications that rely on this key stop working immediately. Make sure you update any systems or services using the key before revoking it. ![Confirm API key revocation](/assets/images/confirm-api-key-deletion-e310b221ffb56e736f2bd8b7e318a351.png) #### Rotate an API key[​](#rotate-an-api-key "Direct link to Rotate an API key") Rotating an API key means replacing an existing key with a new one. This is necessary when your key is approaching its expiration date or if you suspect it may have been compromised. To rotate an API key, follow the steps below: 1. **Create a new API key**
Follow the instructions in [Create API keys](/ssi/overview/security/create-api-keys.md) to generate a new API key. Make sure to copy and store it securely. 2. **Replace the key in your app**
Update all apps, services, and systems that use the old API key with the newly created one. Verify that everything works correctly with the new key before proceeding. 3. **Revoke the old API key**
Once you have confirmed that all your applications are using the new key, [revoke the old API key](#revoke-an-existing-api-key) to ensure it can no longer be used. tip To avoid service interruptions, always create and deploy the new key **before** revoking the old one. **Next steps** After revoking the API key, [create a new API key](/ssi/overview/security/create-api-keys.md) if you need continued access to the Truvity SSI Platform APIs. Make sure that any dependent applications use the new key. --- ### Overview A credential schema is the blueprint for a credential. It defines the structure and meaning of a credential's claims, enabling data consistency and automation. This documentation section is the definitive resource for managing these schemas, providing the tools and concepts necessary to: * **Ensure data integrity** Define schemas that guarantee data consistency for production-ready solutions. * **Facilitate interoperability** Share schemas with external partners to ensure a common understanding of data. * **Control schema evolution** Manage changes to your schemas over time by publishing new, distinct versions. note This section is designed to serve a diverse audience, from developers learning to manage schemas after creating their first credential, to architects seeking robust data governance for their projects. #### The meta-schema: a universal definition[​](#the-meta-schema-a-universal-definition "Direct link to The meta-schema: a universal definition") At the core of the Truvity platform is a universal [**meta-schema**](/ssi/schemas/core-concepts/meta-schema-model.md), which serves as a single source of truth for defining a credential's claims. This meta-schema is **format-agnostic**, which means you define your schema once, and Truvity automatically translates it into the specific format (for example, VCDM schema definition) required for the credentials you issue. This approach ensures that your schemas are always consistent and interoperable across different specifications. #### UDTs: the developer's tool for schema definition[​](#udts-the-developers-tool-for-schema-definition "Direct link to UDTs: the developer's tool for schema definition") For developers using the Truvity SDK, **user-defined types (UDTs)** are the recommended way to define meta-schemas in your code. The SDK automatically translates your UDT into the platform's meta-schema representation, simplifying the process of defining complex credential structures and providing a better developer experience. #### Getting started with schema management[​](#getting-started-with-schema-management "Direct link to Getting started with schema management") After defining your schema with a UDT, you can manage its entire lifecycle. The following sections guide you through this process, from foundational concepts to advanced management techniques. * **[Core concepts](/ssi/schemas/core-concepts/meta-schema-model.md)** Build your foundational knowledge by learning about Truvity's meta-schema model, schema types, and publication principles. * **[Manage schemas](/ssi/schemas/manage-schemas/create-schema.md)** Learn how to perform hands-on tasks, including creating, publishing, versioning, and duplicating schemas using the SDK and API. * **[How-to guides](/ssi/schemas/how-to-guides/prototype-schemas-quickly.md)** Follow end-to-end, scenario-based guides for prototyping schemas and building schema-driven applications. --- ### Meta-schema model The **meta-schema** is a universal, format-agnostic model that serves as the single source of truth for a credential's claim structure and semantic meaning. As a developer, you use this meta-schema to define your credential's data once, and Truvity handles its translation to various formats (for example, W3C Verifiable Credentials Data Model or SD-JWT Verifiable Credentials). This decreases the learning curve for the majority of use cases by eliminating the need to understand all technical details and limitations of credential formats required for issuing and processing credentials. This approach ensures that your schemas are always consistent and interoperable across different ecosystems without you having to manage multiple formats. For developers using the Truvity SDK, **user-defined types (UDTs)** are the recommended way to define a meta-schema in code. The SDK automatically translates your UDT into the platform's meta-schema representation, simplifying the process of defining complex credential structures and providing a better developer experience. To learn how to define a schema for a credential with UDTs, see the **[Define credential schema](/ssi/sdk/credential-lifecycle/define-credential-schema.md)** guide. ### Further reading * [Manage schemas](/ssi/schemas/manage-schemas/create-schema.md) - get hands-on with the practical steps for creating, publishing, and versioning your schemas. --- ### Publication and versioning Once you are ready to move a schema from a temporary development state to a production-ready resource, you must publish it. This page explains the core concepts of publishing and versioning schemas within the Truvity platform. #### Schema publication[​](#schema-publication "Direct link to Schema publication") **Schema publication** is the process of making a schema publicly verifiable, immutable, and discoverable. When you publish a schema, you are essentially creating a permanent, cryptographically protected record of that schema definition. Publication is critical for building trust and ensuring the long-term integrity of the verifiable credentials (VCs) you issue. The key principles of publication are: * **Immutability** Once a schema is published, its definition is permanently frozen and cannot be changed. This guarantees that all credentials issued against that specific version always refer to the exact same schema definition, preventing retroactive changes that could invalidate proofs. * **Provenance** A published schema includes verifiable information about its origin and history, allowing all parties to trust its source. #### Schema versioning[​](#schema-versioning "Direct link to Schema versioning") As real-world data definitions and business requirements evolve, your schemas need to change. **Schema versioning** is the mechanism for managing these changes in a controlled way that respects the principle of immutability. Instead of editing an existing published schema, you create and publish a new version. This ensures: * **Backward compatibility** Existing VCs issued with an older schema version remain valid and verifiable against their original, immutable definition. * **Forward progress** You can introduce new fields or rules in a new schema version, allowing your ecosystem to evolve without breaking old credentials. #### Slugs and versions as public identifiers[​](#slugs-and-versions-as-public-identifiers "Direct link to Slugs and versions as public identifiers") You can identify a published schema by a unique combination of a **slug** and a **version**. * A **slug** is a human-readable identifier (for example, `proof-of-identity`) that groups different versions of the same conceptual schema. * A **version** is a number (for example, `1`, `2`) that denotes a distinct iteration of that schema. The combination of a slug and a version forms a unique, public identifier of a schema. This identifier is a stable URL that verifiers can use to retrieve the schema and validate any credential issued against it. #### Further reading[​](#further-reading "Direct link to Further reading") * [Manage schemas](/ssi/schemas/manage-schemas/create-schema.md) - get hands-on with the practical steps for creating, publishing, and versioning your schemas. --- ### Schema lifecycle and governance The schema lifecycle is an end-to-end process that guides a schema from an idea to a production-ready resource. Understanding this lifecycle is essential for building robust, scalable, and interoperable solutions. This page connects the core concepts of meta-schemas, publication, and versioning into a single, holistic view. #### The schema lifecycle[​](#the-schema-lifecycle "Direct link to The schema lifecycle") The journey of a schema within the Truvity platform follows these key stages: 1. **Creation** You define a structure of a schema and semantic definitions using the [API](/ssi/api-reference.md#tag/schemas/operation/SchemaCreate) or **user-defined types (UDTs)** in your code. At this stage, the schema is a temporary resource used for development and prototyping. 2. **Publication** Once the schema is ready for production, you explicitly publish it. This creates an immutable, publicly verifiable version of your schema with a permanent `slug` and `version`. 3. **Use** Your applications issue verifiable credentials (VCs) that reference the published schema. These credentials can then be verified by any party by accessing the public schema URL. 4. **Evolution** When a schema needs to be updated, you create and publish a new version. This new version can be used for new credentials, while all existing credentials remain valid against their original, immutable schema. #### Schema governance[​](#schema-governance "Direct link to Schema governance") Effective schema management requires thoughtful governance to ensure long-term consistency and trust. Truvity provides tools to support these best practices: * **Version thoughtfully** Always create a new version of a schema when a change is needed. This preserves the immutability of existing credentials. * **Use consistent slugs** The `slug` for a schema should remain consistent across its versions (for example, `proof-of-identity/v1`, `proof-of-identity/v2`). This allows you to group related schemas and track their evolution easily. * **Use faceted search** You can use Truvity's powerful faceted search capabilities to find all versions of a schema by its slug, allowing for easy management of your schema library. ##### **Further reading**[​](#further-reading "Direct link to further-reading") * [Manage schemas](/ssi/schemas/manage-schemas/create-schema.md) - get hands-on with the practical steps for each stage of the schema lifecycle. --- ### Temporary and stable schemas When working with credential schemas, it's helpful to distinguish between two types based on their intended use: **temporary** and **stable**. The type of schema you use depends on whether you are in an active development phase or building a production-ready solution. #### Temporary schemas[​](#temporary-schemas "Direct link to Temporary schemas") A **temporary schema** is a schema that has an adjusted lifecycle specifically aimed at removing obstacles during the active development phase. Such schemas allow any type of changes to their definition without requiring explicit publication until you are ready to finalize your credential data model. While these schemas are great for early development phases, they are not suitable for interoperability with the external world as their semantics are sacrificed for the development speed. #### Stable schemas[​](#stable-schemas "Direct link to Stable schemas") Unlike temporary schemas, a **stable schema** complies with strict [governance rules](/ssi/schemas/core-concepts/schema-lifecycle-and-governance.md) that enable provenance and sharing. Without these rules, Relying Parties (those who verify and process the data) would find it difficult to adopt schemas and the credentials issued with them. Stable schemas are essential for production. Their immutability and public discoverability are foundational for building trust and ensuring that all parties can reliably verify a credential's integrity over time. #### Comparison: temporary and stable schemas[​](#comparison-temporary-and-stable-schemas "Direct link to Comparison: temporary and stable schemas") | Attribute | Temporary Schema | Stable Schema | | -------------- | ----------------------------------- | ------------------------------------------------ | | **Purpose** | Prototyping and testing | Production and interoperability | | **Identifier** | Temporary ID or auto-generated slug | Human-readable `slug` and `version` | | **Provenance** | None | History of changes by version | | **Semantics** | Limited to machine readable | Human readable, easy to understand and integrate | #### Further reading[​](#further-reading "Direct link to Further reading") * [Schema publication and versioning](/ssi/schemas/core-concepts/publication-and-versioning.md) - understand core concepts behind credential schema publishing and versioning. * [Manage schemas](/ssi/schemas/manage-schemas/create-schema.md) - get hands-on with creating, publishing, and versioning schemas. --- ### Build an app for end-users to create and manage dynamic schemas This guide provides a scenario-based walk-through for implementing a backend that allows end users to create, manage, and publish schemas from a custom frontend app. The focus is on the backend logic and the SDK methods that enable this capability. This guide assumes your frontend app provides a UI for defining a schema (for example, a form builder) and that this UI can send a `ClaimsSchema` object to your backend. Prerequisites * [Install and configure the SDK](/ssi/sdk/getting-started/installation.md) #### Part 1: Schema creation workflow[​](#part-1-schema-creation-workflow "Direct link to Part 1: Schema creation workflow") ##### Step 1: Create a new empty schema[​](#step-1-create-a-new-empty-schema "Direct link to Step 1: Create a new empty schema") The first step is to create a new credential schema resource on the Truvity platform. At this point, the schema is empty and the app needs to populate it as the user adds fields in the UI. Use the `SchemaCreate` method for this purpose. * TypeScript * Java ```ts const createdSchema = await client.schemas.schemaCreate({data: {}}); ``` ```java ResourceCredentialSchema createdSchema = client.schemas() .schemaCreate(SchemaCreateRequest.builder() .data(CredentialSchemaCreate.builder() .schema(ClaimsSchemaOptional.builder().build()) .build()) .build()); ``` ##### Step 2: Handle schema updates[​](#step-2-handle-schema-updates "Direct link to Step 2: Handle schema updates") As the user interacts with the UI by adding or removing fields, you can handle schema updates in the backend. Use the `SchemaUpdate` method to apply incremental changes to the credential schema resource by providing the updated `ClaimsSchema`. * TypeScript * Java ```ts const updatedSchema = await client.schemas.schemaUpdate( createdSchema.id, { ifMatch: createdSchema.etag, data: { schema: { fields: [ { name: "name", notEmpty: true, kind: "STRING" }, { name: "year_of_birth", notEmpty: true, kind: "NUMBER" } ] } } } ); ``` ```java ResourceCredentialSchema updatedSchema = client.schemas() .schemaUpdate( createdSchema.getId(), SchemaUpdateRequest.builder() .ifMatch(createdSchema.getEtag()) .data(CredentialSchemaUpdate.builder() .schema(ClaimsSchema.builder() .addFields(ClaimsSchemaFieldsItem.string( ClaimsSchemaFieldStringValue.builder() .name("name") .notEmpty(true) .build())) .addFields(ClaimsSchemaFieldsItem.number( ClaimsSchemaFieldNumberValue.builder() .name("year_of_birth") .notEmpty(true) .build())) .build()) .build()) .build()); ``` ##### Step 3: Publish the schema[​](#step-3-publish-the-schema "Direct link to Step 3: Publish the schema") Once the user finalizes the schema in the UI, you can publish it using the `SchemaPublish` method. This action makes the schema immutable and publicly accessible. The user can provide the `slug` and `version` in the UI or the app can automatically generate them. * TypeScript * Java ```ts const publishedSchema = await client.schemas.schemaPublish( updatedSchema.id, { slug, version } ); ``` ```java ResourcePublishedCredentialSchema publishedSchema = client.schemas() .schemaPublish( updatedSchema.getId(), SchemaPublishRequest.builder() .slug(slug) .version(version) .build()); ``` #### Part 2: Working with the created schema[​](#part-2-working-with-the-created-schema "Direct link to Part 2: Working with the created schema") ##### Step 4: Create a new draft[​](#step-4-create-a-new-draft "Direct link to Step 4: Create a new draft") After the app publishes the schema, the user can use it to create a new credential draft. This example shows how you can create a draft from the previously created schema. * TypeScript * Java ```ts const createdDraft = await client.drafts.draftCreate({ data: { metaSchema: publishedSchema.data.url } }); ``` ```java ResourceDraft createdDraft = client.drafts() .draftCreate(DraftCreateRequest.builder() .data(DraftCreate.builder() .metaSchema(DraftCreateMetaSchema.of( publishedSchema.getData().getUrl())) .build()) .build()); ``` In some cases you need to use a schema from a different tenant when creating a draft, for example when one organization defines structure for credentials it wants to receive. In this case, specify the URL of the schema from another tenant: * TypeScript * Java ```ts const createdDraft = await client.drafts.draftCreate({ data: { metaSchema: "https://ssi.truvity.com/tenants/{tenant_id}/meta-schema/{schema_slug}/v{schema_version}" } }); ``` ```java ResourceDraft createdDraft = client.drafts() .draftCreate(DraftCreateRequest.builder() .data(DraftCreate.builder() .metaSchema(DraftCreateMetaSchema.of( "https://ssi.truvity.com/tenants/{tenant_id}/meta-schema/{schema_slug}/v{schema_version}") .build()) .build()); ``` ##### Step 5: Populate the draft with claims[​](#step-5-populate-the-draft-with-claims "Direct link to Step 5: Populate the draft with claims") The example below shows how the app can populate credential claims in the draft as the user fills in the data in the UI. * TypeScript * Java ```ts await client.drafts.draftUpdate( createdDraft.id, { ifMatch: createdDraft.etag, data: { values: { name: { kind: "STRING", value: "John Doe" }, year_of_birth: { kind: "NUMBER", value: 1985 } } } } ); ``` ```java client.drafts() .draftUpdate( createdDraft.getId(), DraftUpdateRequest.builder() .ifMatch(createdDraft.getEtag()) .data(DraftUpdate.builder() .values(Map.of( "name", CredentialClaimValue.string(StringClaimValue.builder() .value("John Doe") .build()), "year_of_birth", CredentialClaimValue.number(NumberClaimValue.builder() .value(1985) .build()))) .build()) .build()); ``` ##### Step 6: Issue the credential and retrieve credential claims[​](#step-6-issue-the-credential-and-retrieve-credential-claims "Direct link to Step 6: Issue the credential and retrieve credential claims") Once the user completes the draft, you can issue the credential. The `draftLatestIssue` method makes the credential immutable and verifiable. You can then use the `CredentialClaimValues` method to retrieve the credential claims in a format-independent way for display in the user interface. * TypeScript * Java ```ts const issuedVc = await client.drafts.draftLatestIssue( createdDraft.descriptor.id, { keyId: privateKeyId } ); const issuedVcClaims = await client.credentials.getCredentialClaimValues(issuedVc.id); ``` ```java var issuedVc = client.drafts() .draftLatestIssue( createdDraft.getId(), DraftLatestIssueRequest.builder() .keyId(privateKeyId) .build()); var issuedVcClaims = client.credentials().getCredentialClaimValues(issuedVc.getId()); ``` #### Part 3: Schema evolution workflow[​](#part-3-schema-evolution-workflow "Direct link to Part 3: Schema evolution workflow") This workflow describes how your backend can handle the evolution of an existing, published schema. It starts with displaying an existing schema in the UI, allowing the user to make changes, and then publishing a new version of the schema. ##### Step 7: Search for and display an existing schema[​](#step-7-search-for-and-display-an-existing-schema "Direct link to Step 7: Search for and display an existing schema") When a user selects an existing schema from the UI (for example, `Payment/v1`), your backend first searches and retrieves it. Use the `PublishedSchemaSearch` method to find a schema by its slug and version, or the `PublishedSchemaLatest` method to retrieve it by its ID. * TypeScript * Java ```ts const foundPublishedSchemas = await client.publishedSchemas.publishedSchemaSearch({ filter: [ { data: { slug: { operator: "EQUAL", value: slug } } }, { data: { version: {operator: "EQUAL", value: version } } } ] }); const publishedSchema = foundPublishedSchemas.items[0]; // alternatively const publishedSchema = await client.publishedSchemas.publishedSchemaLatest(schemaId); ``` ```java ListPublishedCredentialSchema foundPublishedSchemas = client.publishedSchemas() .publishedSchemaSearch(PublishedSchemaSearchRequest.builder() .filter(List.of( PublishedSchemaBaseFilter.builder() .data(PublishedSchemaFilterData.builder() .slug(PublishedSchemaFilterDataSlug.equal(slug)) .build()) .build(), PublishedSchemaBaseFilter.builder() .data(PublishedSchemaFilterData.builder() .version(PublishedSchemaFilterDataVersion.equal(version)) .build()) .build())) .build()); ResourcePublishedCredentialSchema publishedSchema = foundPublishedSchemas.getItems().get(0); // alternatively ResourcePublishedCredentialSchema publishedSchema = client.publishedSchemas().publishedSchemaLatest(schemaId); ``` ##### Step 8: Copy and update the new schema[​](#step-8-copy-and-update-the-new-schema "Direct link to Step 8: Copy and update the new schema") When the user wants to modify the schema in the UI (for example, to add a new field), your backend should create a new credential schema resource based on the original. This adheres to the principle of immutability. Use the `SchemaCreate` method with the `fromPublishedMetaSchemaUrl` parameter for this purpose. Use the `SchemaUpdate` method to apply the changes from the UI. * TypeScript * Java ```ts const copiedSchema = await client.schemas.schemaCreate({ data: { fromPublishedSchemaUrl: publishedSchema.data.url } }); await client.schemas.schemaUpdate( copiedSchema.id, { ifMatch: copiedSchema.etag, data: { schema: updatedClaimsSchema } } ); ``` ```java ResourceCredentialSchema copiedSchema = client.schemas() .schemaCreate(SchemaCreateRequest.builder() .data(CredentialSchemaCreate.builder() .fromPublishedSchemaUrl(publishedSchema.getData().getUrl()) .build()) .build()); client.schemas() .schemaUpdate( copiedSchema.getId(), SchemaUpdateRequest.builder() .ifMatch(copiedSchema.getEtag()) .data(CredentialSchemaUpdate.builder() .schema(updatedClaimsSchema) .build()) .build()); ``` ##### Step 9: Publish the new schema version[​](#step-9-publish-the-new-schema-version "Direct link to Step 9: Publish the new schema version") Once the user finalizes their changes, they can publish the new schema as a new version. Use the `schemaPublish` method for this purpose. The user can either provide a new version number in the UI or the app can append it automatically. * TypeScript * Java ```ts const publishedCopiedSchema = await client.schemas.schemaPublish(copiedSchema.id, { slug, version }); ``` ```java ResourcePublishedCredentialSchema publishedCopiedSchema = client.schemas() .schemaPublish( copiedSchema.getId(), SchemaPublishRequest.builder() .slug(slug) .version(version) .build()); ``` #### What's next[​](#whats-next "Direct link to What's next") After you create and publish a schema, your app's backend is responsible for implementing the subsequent business logic. Truvity provides the tools to create and manage schemas, but the processing and validation of credential data against the schema are specific to your use case. Your next steps typically involve: * **Retrieve Credential Claims:** Once a Verifiable Credential (VC) is created, retrieve its claim values. * **Implement Business Logic:** Process and validate the data according to your app's requirements. This might include comparing the claims of the VC against the schema definitions, running custom validation rules, or performing other logic specific to your business needs. This business-specific logic must be coded within your app. #### Further reading[​](#further-reading "Direct link to Further reading") * [Create a schema](/ssi/schemas/manage-schemas/create-schema.md) - Learn how to create schemas programmatically with UDTs. * [Use an external schema](/ssi/schemas/manage-schemas/use-external-schema.md) - Learn how to handle schemas from external sources. --- ### Quickly prototype schemas This guide provides a hands-on walk-through of the end-to-end workflow for rapid prototyping with static schemas using the SDK. This approach allows you to define, publish, version, and test schemas to iterate on your solution quickly. Prerequisites * [Install and configure the SDK](/ssi/sdk/getting-started/installation.md) #### Step 1: Define a schema with a UDT[​](#step-1-define-a-schema-with-a-udt "Direct link to Step 1: Define a schema with a UDT") First, define a schema using **user-defined types (UDTs)** in your code. Use the `@VcSchema` decorator to define a unique identifier (`slug`) and a `version` number of the schema. * TypeScript * Java ```ts // Define a UDT for a "basic profile" credential schema @VcSchema({ slug: 'basic-profile', version: 1 }) export class BasicProfileClaims { @VcNotEmptyClaim firstName!: string; lastName?: string; } ``` ```java // Define a UDT for a "basic profile" credential schema @VcSchema(slug = "basic-profile", version = 1) class BasicProfileClaims { @NotEmpty String firstName; String lastName; } ``` #### Step 2: Publish the schema[​](#step-2-publish-the-schema "Direct link to Step 2: Publish the schema") Next, publish the schema using the `VcDecorator` from your UDT. The `publishSchema()` method sends the schema to the Truvity platform, making it immutable and publicly accessible for verification. important Once a schema is published, its definition is permanently frozen and cannot be changed. This is a core principle of Verifiable Credentials. To make changes, you must publish a new version of the schema. * TypeScript * Java ```ts // Create a decorator from your UDT const basicProfileDecorator = client.createVcDecorator(BasicProfileClaims); // Publish the schema try { await basicProfileDecorator.publishSchema(); console.log('Schema published successfully!'); } catch (error) { console.error('Failed to publish schema:', error); } ``` ```java // Create a decorator from your UDT VcDecorator basicProfileDecorator = client.vcDecorator(BasicProfileClaims.class); // Publish the schema SchemaPublicationResult result = basicProfileDecorator.publishSchema(); if (result.published) { System.out.println("Schema published successfully"); } else { System.out.println("Failed to publish schema: " + result.error); } ``` #### Step 3: Test interoperability[​](#step-3-test-interoperability "Direct link to Step 3: Test interoperability") The published schema can now be used to issue a verifiable credential. Any party can then verify the credential against the public definition of the schema, proving its interoperability. You can also retrieve the public URL of the schema for discoverability and sharing. * TypeScript * Java ```ts // Create a draft using the published schema const createdDraft = await basicProfileDecorator.create({ claims: { firstName: 'John', lastName: 'Doe' } }); // Generate a private key for signing if it doesn't exist const privateKey = await client.keys.keyGenerate({ data: { type: 'P256' } }); // Issue a credential from the draft const issuedCredential = await createdDraft.issue(privateKey.id); // Verify the credential const isVerified = await issuedCredential.verify(); if (isVerified) { console.log('Credential verified successfully!'); } else { console.log('Credential verification failed.'); } ``` ```java // Create a draft using the published schema DraftCredentialWithClaims createdDraft = basicProfileDecorator.create(new BasicProfileClaims() { { claims.firstname = "John"; claims.lastName = "Doe"; } }); // Generate a private key for signing if it doesn't exist ResourceKeyPublic privateKey = client.keys() .keyGenerate(KeyGenerateRequest.builder() .data(KeyGenerate.builder().type(KeyGenerateType.P_256).build()) .build()); // Issue a credential from the draft VerifiableCredentialWithClaims issuedCredential = createdDraft.issue(privateKey.getId()); // Verify the credential VerificationResult verificationResult = issuedCredential.verify(); if (verificationResult.verified()) { System.out.println("Credential verified successfully!"); } else { System.out.println("Credential verification failed."); } ``` #### Step 4: Create and publish a new schema version[​](#step-4-create-and-publish-a-new-schema-version "Direct link to Step 4: Create and publish a new schema version") As part of the credential schema lifecycle, you most likely need to make updates to a published schema to align with new business or regulatory requirements. To make a change to the schema, you must create a new version. Define a new UDT with an incremented version number and your changes, and then publish it. * TypeScript * Java ```ts // Define an updated UDT for the "basic profile" credential schema to version 2 @VcSchema({ slug: 'basic-profile', version: 2 }) export class BasicProfileClaimsV2 { @VcNotEmptyClaim firstName!: string; lastName?: string; // Add a new field birthDate?: Rfc3339Date; } // Create a decorator from the new UDT const basicProfileDecoratorV2 = client.createVcDecorator(BasicProfileClaimsV2); // Publish the new version try { await basicProfileDecoratorV2.publishSchema(); console.log('Schema v2 published successfully!'); } catch (error) { console.error('Failed to publish schema:', error); } ``` ```java // Define an updated UDT for the "basic profile" credential schema to version 2 @VcSchema(slug = "basic-profile", version = 2) class BasicProfileClaimsV2 { @NotEmpty String firstName; String lastName; // Add a new field LocalDate birthDate; } // Create a decorator from the new UDT VcDecorator basicProfileDecoratorV2 = client.vcDecorator(BasicProfileClaimsV2.class); // Publish the new version SchemaPublicationResult result = basicProfileDecoratorV2.publishSchema(); if (result.published) { System.out.println("Schema v2 published successfully"); } else { System.out.println("Failed to publish schema: " + result.error); } ``` Tip If you want to only add new fields when extending an existing schema definition, you don't need to copy and paste the full UDT definition and can use class extension instead. The following example shows how to do that. * TypeScript * Java ```ts // Define an updated UDT for the "basic profile" credential schema to version 2 @VcSchema({ slug: 'basic-profile', version: 2 }) export class BasicProfileClaimsV2 extends BasicProfileClaims { // Add a new field birthDate?: Rfc3339Date; } ``` ```java // Define an updated UDT for the "basic profile" credential schema to version 2 @VcSchema(slug = "basic-profile", version = 2) class BasicProfileClaimsV2 extends BasicProfileClaims { // Add a new field LocalDate birthDate; } ``` #### Step 5: Test interoperability of a new schema version[​](#step-5-test-interoperability-of-a-new-schema-version "Direct link to Step 5: Test interoperability of a new schema version") Finally, test the interoperability of the new schema version by creating and verifying a credential. * TypeScript * Java ```ts // Create a draft using the latest published schema (v2) const createdDraftV2 = await basicProfileDecoratorV2.create({ claims: { firstName: 'John', lastName: 'Doe', birthDate: new Rfc3339Date('1990-01-01') } }); // Assume 'privateKey' is the private key generated in a previous step const issuedCredentialV2 = await createdDraftV2.issue(privateKey.id); // Verify the credential const isVerifiedV2 = await issuedCredentialV2.verify(); if (isVerifiedV2) { console.log('Credential v2 verified successfully!'); } else { console.log('Credential v2 verification failed.'); } ``` ```java // Create a draft using the latest published schema (v2) DraftCredentialWithClaims createdDraftV2 = basicProfileDecoratorV2.create(new BasicProfileClaimsV2() { { firstName = "John"; lastName = "Doe"; birthDate = LocalDate.of(1990, 1, 1); } }); // Assume 'privateKey' is the private key generated in a previous step VerifiableCredentialWithClaims issuedCredentialV2 = createdDraftV2.issue(privateKey.getId()); // Verify the credential VerificationResult verificationResultV2 = issuedCredentialV2.verify(); if (verificationResultV2.verified()) { System.out.println("Credential v2 verified successfully!"); } else { System.out.println("Credential v2 verification failed."); } ``` #### Further reading[​](#further-reading "Direct link to Further reading") * [Build a frontend app for end users to create and manage schemas](/ssi/schemas/how-to-guides/build-app-for-end-users-to-manage-schemas.md) - learn how to build a production-ready app for dynamic schema management on the end-user side. --- ### Create a schema Before a credential schema can be published and used in a production environment, you must define it. This page provides a practical guide to creating a schema definition. You can create schemas using two methods: 1. **Using the SDK**: The recommended method for defining schemas programmatically within your code. 2. **Using the API**: The method for creating schemas with a non-SDK client. #### Use the SDK to define a schema[​](#use-the-sdk-to-define-a-schema "Direct link to Use the SDK to define a schema") Prerequisites * [Install and configure the SDK](/ssi/sdk/getting-started/installation.md) The easiest way to define a schema is by creating a **user-defined type (UDT)** in your code. The UDT serves as the blueprint for your schema and is associated with it via the `@VcSchema` decorator. This approach provides compile-time type safety and simplifies the schema definition process. For a detailed guide on how to define schemas with various data types and code examples, refer to the [Define a credential schema](/ssi/sdk/credential-lifecycle/define-credential-schema.md) SDK guide. * TypeScript * Java ```ts // Define a UDT for a basic proof of identity @VcSchema({ slug: 'proof-of-identity', version: 1 }) export class ProofOfIdentity { @VcNotEmptyClaim firstName!: string; @VcNotEmptyClaim lastName!: string; } // In your application, this UDT is used to create a decorator const proofOfIdentity = client.createVcDecorator(ProofOfIdentity); // You can now create a draft or publish the schema for production ``` ```java // Define a UDT for a basic proof of identity @VcSchema(slug = "proof-of-identity", version = 1) class ProofOfIdentity { @NotEmpty String firstName; @NotEmpty String lastName; } // In your application, this UDT is used to create a decorator VcDecorator proofOfIdentity = client.vcDecorator(ProofOfIdentity.class); // You can now create a draft or publish the schema for production ``` The `VcSchema` decorator accepts the following options: * `slug` - optional string. If the slug is not provided, this schema is considered temporary. You cannot publish the schema without a slug. * `version` - optional number. If the version is not provided, the platform defaults to `version=1`. * `owner` - optional string, which is a `tenantId` of the schema owner (another Truvity tenant). If provided, the platform uses a schema published by that owner. This establishes trust - for example, when issuing a credential that is based on the schema published by the government, you want to ensure you use a government-published schema, as verifiers only trust the government-owned schemas for such important information. #### Use the API to create a schema[​](#use-the-api-to-create-a-schema "Direct link to Use the API to create a schema") Prerequisites * [Create an API key](/ssi/overview/security/create-api-keys.md) For direct API access, you can create a new schema resource using the `POST` [`/schemas`](/ssi/api-reference.md#tag/schemas/operation/SchemaCreate) endpoint. This method requires you to provide a `schema` JSON object, which is Truvity's universal meta-schema model. This approach is useful for building applications that generate schemas dynamically (for example, from a frontend) or for integrating with non-SDK clients. The [following how-to guide](/ssi/schemas/how-to-guides/build-app-for-end-users-to-manage-schemas.md) explains how to create applications that work with dynamic schemas created by end users. #### Further reading[​](#further-reading "Direct link to Further reading") * [Publish a schema](/ssi/schemas/manage-schemas/publish-schema.md) * [Duplicate an existing schema](/ssi/schemas/manage-schemas/duplicate-schema.md) --- ### Duplicate a schema Creating a new schema based on an existing one is a common practice for developing new versions, creating localized variants, or simply using a pre-existing schema as a template. This process, called duplication, allows you to leverage existing work without altering the original schema. #### Using the SDK[​](#using-the-sdk "Direct link to Using the SDK") Prerequisites * [Install and configure the SDK](/ssi/sdk/getting-started/installation.md) * [Create a credential schema](/ssi/schemas/manage-schemas/create-schema.md) When using the SDK, a schema is defined as a class. To duplicate a schema, you can either copy the UDT definition and create a new class or use class extension. This allows you to easily create a new schema resource based on an existing one. The example below shows how to duplicate a schema using class extension: * TypeScript * Java ```ts // Existing UDT definition @VcSchema({ slug: 'proof-of-identity' }) export class ProofOfIdentity { @VcNotEmptyClaim firstName!: string; @VcNotEmptyClaim lastName!: string; } // Duplicated UDT using class extension @VcSchema({ slug: 'duplicated-proof-of-identity' }) export class DuplicatedProofOfIdentity extends ProofOfIdentity { } ``` ```java // Existing UDT definition @VcSchema(slug = "proof-of-identity") class ProofOfIdentity { @NotEmpty String firstName; @NotEmpty String lastName; } // Duplicated UDT using class extension @VcSchema(slug = "duplicated-proof-of-identity") class DuplicatedProofOfIdentity extends ProofOfIdentity {} ``` #### Using the API[​](#using-the-api "Direct link to Using the API") Prerequisites * [Create an API key](/ssi/overview/security/create-api-keys.md) To duplicate a schema using the API, use the `POST` [`/schemas`](/ssi/api-reference.md#tag/schemas/operation/SchemaCreate) endpoint. This endpoint allows you to create a new schema by referencing an existing one using either its internal ID or its public URL. ##### From an internal schema ID[​](#from-an-internal-schema-id "Direct link to From an internal schema ID") This method is useful for duplicating a schema that has not yet been published, or one that is only available within your tenant. You must have the ID of the original schema. To duplicate the schema, use the `POST` [`/schemas`](/ssi/api-reference.md#tag/schemas/operation/SchemaCreate) endpoint and provide the following in the request body: ```json { "from_schema": "b4d2e7a1-c9f3-d5a8-b7c6-e1f0a3b9c2d5", "labels": { "variant": "german" } } ``` ##### From a public URL[​](#from-a-public-url "Direct link to From a public URL") This method is useful for duplicating a schema that has been published by another tenant or is publicly available. You must use the full public URL of the schema. To duplicate the schema, use the `POST` [`/schemas`](/ssi/api-reference.md#tag/schemas/operation/SchemaCreate) endpoint and provide the following in the request body: ```json { "from_published_schema_url": "https://ssi.truvity.com/tenants/123/schemas/meta/basic-profile/v1" } ``` #### Further reading[​](#further-reading "Direct link to Further reading") * [Version a schema](/ssi/schemas/manage-schemas/version-schema.md) * [Publish a schema](/ssi/schemas/manage-schemas/publish-schema.md) --- ### Publish a schema Publishing a schema is the final step to making it an immutable, publicly verifiable, and production-ready resource. This page provides a practical guide on how to publish a schema that you have already defined. Publishing a schema is an explicit action that creates a permanent record of the schema definition. Once a schema is published, it cannot be modified. #### Using the SDK[​](#using-the-sdk "Direct link to Using the SDK") Prerequisites * [Install and configure the SDK](/ssi/sdk/getting-started/installation.md) * [Create a schema](/ssi/schemas/manage-schemas/create-schema.md) The easiest way to publish a schema is by using the `publishSchema()` method on a `VcDecorator` instance. When you call this method, the SDK publishes the schema defined by the user-deinfed types (UDTs) and makes it available on the Truvity platform. The `slug` and `version` parameters in your UDT's `@VcSchema` decorator are used to identify the published schema. * TypeScript * Java ```ts // Create a decorator from your UDT const proofOfIdentity = client.createVcDecorator(ProofOfIdentity); // Publish the schema for production await proofOfIdentity.publishSchema(); ``` ```java // Create a decorator from your UDT VcDecorator proofOfIdentity = client.vcDecorator(ProofOfIdentity.class); // Publish the schema for production proofOfIdentity.publishSchema(); ``` important * If the schema is already published, the platform performs no action. * If the schema is already published but there were changes in the UDT definition, this operation shows an error. * It is recommended to set up schema publication outside the main app workflow to avoid unnecessary API requests. #### Using the API[​](#using-the-api "Direct link to Using the API") Prerequisites * [Create an API key](/ssi/overview/security/create-api-keys.md) For direct API access, you can publish a schema using the `PATCH` [`/schemas/{id}/publish endpoint`](/ssi/api-reference.md#tag/schemas/operation/SchemaPublish). You must have the resource ID of the CredentialSchema you want to publish. The request payload requires a slug and an optional version to identify the published schema. ```json { "slug": "basic-profile", "version": 1 } ``` #### Further reading[​](#further-reading "Direct link to Further reading") * [Version a schema](/ssi/schemas/manage-schemas/version-schema.md) * [Duplicate an existing schema](/ssi/schemas/manage-schemas/duplicate-schema.md) --- ### Work with an external schema Truvity credential schemas are designed for interoperability with other self-sovereign identity (SSI) ecosystems and industry standards. This page provides a practical guide on how to work with schema definitions that originate outside of the Truvity platform. You can use external schemas in two ways: 1. **Using the SDK**: The recommended method for defining schemas programmatically within your code. 2. **Using the API**: The method for advanced users or for creating schemas with a non-SDK client. important Considerations and limitations: * **Validation responsibility**: When referencing external schemas, the Truvity platform does not validate your UDT structure against the external schemas at compile time or upon issuance. It is your responsibility to ensure that your UDT claim definitions accurately match the external schema structure. * **Developer experience improvement**: Despite the lack of compile-time validation, using UDTs still significantly improves developer experience compared to manual JSON manipulation for external schemas, as it handles basic type-safe serialization and deserialization. * **UDT generation**: Direct UDT generation from arbitrary external schemas is currently not supported. #### Using the SDK[​](#using-the-sdk "Direct link to Using the SDK") Prerequisites * [Install and configure the SDK](/ssi/sdk/getting-started/installation.md) The `@VcExternalSchema` decorator allows you to specify external JSON-LD vocabularies and JSON schemas that your UDT should reference during credential issuance. This decorator is used in conjunction with the `@VcSchema` decorator to define an external schema. ##### Augmenting a managed schema[​](#augmenting-a-managed-schema "Direct link to Augmenting a managed schema") This method is useful when your Truvity-managed schema needs to use terms or contexts from a well-known external semantic definition. * TypeScript * Java ```ts @VcSchema({ slug: 'proof-of-identity' }) @VcExternalSchema({ jsonLdVocabs: [ VcSchema.jsonLdVocabUrl, // Special symbol: SDK will replace with the URL of the published JSON-LD context 'https://www.w3.org/ns/credentials/examples/v2', // An example external w3.org context ], }) export class ProofOfIdentity { @VcNotEmptyClaim firstName!: string; @VcNotEmptyClaim lastName!: string; } ``` ```java @VcSchema(slug = "proof-of-identity") @VcExternalSchema( jsonLdVocabs = { VcSchema.jsonLdVocabUrl, // Special symbol: SDK will replace with the URL of the published JSON-LD context "https://www.w3.org/ns/credentials/examples/v2", // An example external w3.org context } ) class ProofOfIdentity { @NotEmpty String firstName; @NotEmpty String lastName; } ``` ##### Using a fully external schema[​](#using-a-fully-external-schema "Direct link to Using a fully external schema") This method is useful when you want to create a UDT that is based entirely on external schemas. The UDT in this case acts as a type-safe wrapper for the external schema. * TypeScript * Java ```ts @VcExternalSchema({ jsonLdVocabs: ['https://www.w3.org/ns/credentials/examples/v2'], vcJsonSchemas: ['https://example.com/schemas/email.json'], }) export class ProofOfIdentity { @VcNotEmptyClaim firstName!: string; @VcNotEmptyClaim lastName!: string; } ``` ```java @VcSchema @VcExternalSchema( jsonLdVocabs = {"https://www.w3.org/ns/credentials/examples/v2"}, vcJsonSchemas = {"https://example.com/schemas/email.json"}) class ProofOfIdentity { @NotEmpty String firstName; @NotEmpty String lastName; } ``` #### Using the API[​](#using-the-api "Direct link to Using the API") Prerequisites * [Create an API key](/ssi/overview/security/create-api-keys.md) For direct API access, you can reference external schemas when you create a draft using the `POST` [`/drafts`](/ssi/api-reference.md#tag/drafts/operation/DraftCreate) endpoint. The request payload has `json_ld_vocabs` and `vcdm_json_schemas` properties that you can use to reference external schemas directly: ```json { "data": { "vcdm_json_schemas": [ "https://example.com/schemas/email.json" ], "values": { "emailAddress": { "kind": "STRING", "value": "john.doe@example.com" } } } } ``` #### Further reading[​](#further-reading "Direct link to Further reading") * [Publish a schema](/ssi/schemas/manage-schemas/publish-schema.md) * [Version a schema](/ssi/schemas/manage-schemas/version-schema.md) --- ### Version a schema Schema versioning is the mechanism for managing changes to a schema over time while preserving the immutability of existing published versions. This process ensures that old credentials remain valid against their original schema, and new credentials can be issued against an updated definition. To create a new version of a schema, you must first create a new credential schema resource, make your changes, and then publish it with an incremented version number. #### Using the SDK[​](#using-the-sdk "Direct link to Using the SDK") Prerequisites * [Install and configure the SDK](/ssi/sdk/getting-started/installation.md) * [Create a schema](/ssi/schemas/manage-schemas/create-schema.md) * [Publish a schema](/ssi/schemas/manage-schemas/publish-schema.md) The easiest way to create a new version of a schema is to define a new **user-defined types (UDTs)** definition with an incremented `version` number. You can then make your changes to the new UDT definition and [publish it](/ssi/schemas/manage-schemas/publish-schema.md). * TypeScript * Java ```ts // Existing UDT definition for v1 @VcSchema({ slug: 'proof-of-identity', version: 1 }) export class ProofOfIdentityV1 { @VcNotEmptyClaim firstName!: string; @VcNotEmptyClaim lastName!: string; @VcNotEmptyClaim identityNumber!: number; } // New UDT for v2 with an updated field type @VcSchema({ slug: 'proof-of-identity', version: 2 }) export class ProofOfIdentityV2 { @VcNotEmptyClaim firstName!: string; @VcNotEmptyClaim lastName!: string; @VcNotEmptyClaim identityNumber!: string; // Updated field type } ``` ```java // Existing UDT definition for v1 @VcSchema(slug = "proof-of-identity", version = 1) class ProofOfIdentityV1 { @NotEmpty String firstName; @NotEmpty String lastName; @NotEmpty double identityNumber; } // New UDT for v2 with an updated field type @VcSchema(slug = "proof-of-identity", version = 2) class ProofOfIdentityV2 { @NotEmpty String firstName; @NotEmpty String lastName; @NotEmpty String identityNumber; } ``` Tip If you want to only add new fields when extending an existing schema definition, you don't need to copy and paste the full UDT definition and can use class extension instead. The example below shows how to do it. * TypeScript * Java ```ts // Existing UDT definition for v1 @VcSchema({ slug: 'proof-of-identity' }) export class ProofOfIdentity { @VcNotEmptyClaim firstName!: string; @VcNotEmptyClaim lastName!: string; } // New UDT for v2 with an added field @VcSchema({ slug: 'proof-of-identity', version: 2 }) export class ProofOfIdentityV2 extends ProofOfIdentity { @VcNotEmptyClaim dateOfBirth!: Rfc3339Date; // New field for v2 } ``` ```java // Existing UDT definition for v1 @VcSchema(slug = "proof-of-identity") class ProofOfIdentity { @NotEmpty String firstName; @NotEmpty String lastName; } // New UDT for v2 with an added field @VcSchema(slug = "proof-of-identity", version = 2) class ProofOfIdentityV2 extends ProofOfIdentity { @NotEmpty LocalDate dateOfBirth; // New field for v2 } ``` #### Using the API[​](#using-the-api "Direct link to Using the API") Prerequisites * [Create an API key](/ssi/overview/security/create-api-keys.md) For direct API access, the workflow for creating a new version involves three steps: 1. `Duplicate` the existing schema resource. 2. `Modify` the schema to include your changes. 3. `Publish` the modified schema with a new version number. This example assumes you have the ID of a credential schema that you want to version. 1. Use the `POST` [`/schemas`](/ssi/api-reference.md#tag/schemas/operation/SchemaCreate) endpoint to duplicate the existing schema: ```json { "from_schema": "b4d2e7a1-c9f3-d5a8-b7c6-e1f0a3b9c2d5" } ``` This request returns the resource ID of the new, duplicated schema. 2. Use the `PATCH` [`/schemas/{id}`](/ssi/api-reference.md#tag/schemas/operation/SchemaUpdate) endpoint to modify the new schema resource: ```json { "data": { "schema": { "fields": [ { "kind": "STRING", "name": "projectName" }, { "kind": "STRING", "name": "projectStatus" // Add the new field } ] } } } ``` 3. Use the `PATCH` [`/schemas/{id}/publish`](/ssi/api-reference.md#tag/schemas/operation/SchemaPublish) to [publish the modified schema](/ssi/schemas/manage-schemas/publish-schema.md) as a new version: ```json { "slug": "project-credentials", "version": 2 } ``` #### Further reading[​](#further-reading "Direct link to Further reading") * [Duplicate a schema](/ssi/schemas/manage-schemas/duplicate-schema.md) - Learn how to copy an existing schema. * [Publish a schema](/ssi/schemas/manage-schemas/publish-schema.md) - Learn how to publish the schema you just created. --- ### SDK overview The Truvity Software Development Kit (SDK) provides a set of tools and libraries to help developers integrate Self-Sovereign Identity (SSI) capabilities into their apps. It simplifies managing verifiable credentials (VCs) and verifiable presentations (VPs) while adhering to SSI standards. #### What is an SDK?[​](#what-is-an-sdk "Direct link to What is an SDK?") An SDK provides developers with the tools and resources needed to interact with a specific system, such as an API. While SDKs often contain code libraries, they encompass much more than just code. An SDK typically includes comprehensive documentation, code samples, developer guides, and additional tools like command-line tools that aid in development. Think of an SDK like a construction set - everything you need to build a specific project is included in one package. Instead of building an integration from scratch, an SDK provides the essential components and instructions to help accelerate development, allowing you to focus on the unique logic and features of your app. SDKs handle many standard operations for you, so you can spend more time on what makes your app stand out. #### Introduction to the Truvity SDK[​](#introduction-to-the-truvity-sdk "Direct link to Introduction to the Truvity SDK") The Truvity SDK is a key component of the Truvity Platform, enabling developers to manage digital wallets and the lifecycle of verifiable credentials. It abstracts the complexity of implementing SSI, allowing you to quickly build secure, interoperable apps that handle identities, credentials, and secure communication. #### Key features[​](#key-features "Direct link to Key features") The Truvity SDK offers the following core features: ##### API clients[​](#api-clients "Direct link to API clients") The Truvity SDK includes API clients that provide seamless access to Truvity APIs. These clients enable you to perform key operations such as: * Creating drafts * Creating, issuing, and verifying verifiable credentials (VCs) and verifiable presentations (VPs) * Managing credential schemas * Facilitating secure data exchange between entities using DIDComm messaging * Attaching labels to [REST resources](/ssi/overview/reference/rest-resources-operations.md) * Searching and filtering [REST resources](/ssi/overview/reference/rest-resources-operations.md) and their content * Sharing verifiable credentials and verifiable presentations using DIDComm messaging * And more ##### User-defined types (UDTs)[​](#user-defined-types-udts "Direct link to User-defined types (UDTs)") [**User-defined types (UDTs)**](/ssi/sdk/credential-lifecycle/user-defined-types.md) allow you to create custom data models for credential schemas and simplify management of credential lifecycle. With UDTs, you can define custom credential types tailored to your organization's needs, and minimize errors by ensuring consistent data structures. #### Getting started[​](#getting-started "Direct link to Getting started") To start using the Truvity SDK, see the [Quick start guide](/ssi/sdk/getting-started/quick-start.md) for detailed instructions on installation, configuration, and first steps in your preferred language. #### Further reading[​](#further-reading "Direct link to Further reading") For more in-depth information on specific features and capabilities, explore: * [API documentation](/ssi/api-reference.md) * [Credential lifecycle management](/ssi/sdk/credential-lifecycle/drafts-vs-credentials.md) * [User-defined types (UDTs)](/ssi/sdk/credential-lifecycle/user-defined-types.md) --- ### API clients overview API Clients simplify interaction with the core platform by abstracting the low-level API calls into high-level methods that are easier to use and integrate into your applications. Each client offers a consistent API surface but is tailored to its respective language. They handle the communication with the underlying SSI system, including authentication and data retrieval. info While there is no comprehensive API Client reference at the moment, you can rely on their IDE for method exploration or refer to the [API Documentation](/ssi/api-reference.md), which includes code samples for each language (except Java). --- ### Create a draft from defined credential schema The `VcDecorator` represents the entry point for the [UDT model](/ssi/sdk/credential-lifecycle/user-defined-types.md) and the lifecycle of the credential (Create → Update → Issue → Present). This page covers the first step of the credential lifecycle - creating a draft resource from a previously defined credential schema. Prerequisites * [Install and configure the SDK](/ssi/sdk/getting-started/installation.md) * [Define credential schema](/ssi/sdk/credential-lifecycle/define-credential-schema.md) #### Example: Create a draft with basic claims[​](#example-create-a-draft-with-basic-claims "Direct link to Example: Create a draft with basic claims") The example below takes the previously defined [basic credential schema](/ssi/sdk/credential-lifecycle/define-credential-schema.md), creates the `VcDecorator` instance and adds claims to the `Draft` resource: * TypeScript * Java ```ts const vcDecoratorInstance = await client.createVcDecorator(ClaimsModelExample); // VcDecorator const createdDraft = await vcDecoratorInstance.create({ // Draft claims: { name: "Alice", age: 30 } }); ``` ```java VcDecorator vcDecoratorInstance = client.vcDecorator(ClaimsModelExample.class); ClaimsModelExample claimsModelData = new ClaimsModelExample(); claimsModelData.setName("Alice"); claimsModelData.setAge(30); var createdDraft = vcDecoratorInstance.create(claimsModelData); ``` important The `createVcDecorator` method creates a new draft using the API and returns its representation (the `Draft` instance). This returns a draft instance with the assigned claims model passed to the `VcDecorator`. In the preceding example, the claims model is `ClaimsModelExample`. Once created, you can update the draft as needed or issue a verifiable credential (VC). #### Example: Create a draft with date and date-time claims[​](#example-create-a-draft-with-date-and-date-time-claims "Direct link to Example: Create a draft with date and date-time claims") The example below shows how to add date-based claims values the previously defined [credential schema with dates](/ssi/sdk/credential-lifecycle/define-credential-schema.md): * TypeScript * Java ```ts const vcDecoratorInstance = await client.createVcDecorator(ClaimsModelExample); // VcDecorator const createdDraft = await vcDecoratorInstance.create({ claims: { field1: new Rfc3339Date(1992, 10, 15), field2: new Rfc3339DateTime(), // Current date and time } }); ``` ```java ClaimsModelExample claimsModelData = new ClaimsModelExample(); claimsModelData.setField1(LocalDate.of(1992, 10, 15)); claimsModelData.setField2(OffsetDateTime.now()); var createdDraft = vcDecoratorInstance.create(claimsModelData)); ``` important Remember these key points about working with `Rfc3339DateTime` when passing it as a string: 1. Always use UTC times (indicated by the `Z` at the end of the string representation). 2. Use the following format: `YYYY-MM-DDTHH:mm:ss.sssZ`. #### Further reading[​](#further-reading "Direct link to Further reading") * [Drafts vs credentials](/ssi/sdk/credential-lifecycle/drafts-vs-credentials.md) * [Update a draft](/ssi/sdk/credential-lifecycle/update-draft.md) * [Link credentials](/ssi/sdk/linked-data/link-credentials.md) * [Issue a credential](/ssi/sdk/credential-lifecycle/issue-credential.md) --- ### Define a credential schema #### What is a credential schema?[​](#what-is-a-credential-schema "Direct link to What is a credential schema?") A [credential schema](/ssi/overview/core-concepts/credential-schemas.md) defines the structure of **claims** for a specific type of credential. Credential schemas ensure that credentials follow a consistent structure, making them easier to validate, share, and verify. To represent static schemas created in the app code, follow this page to use **user-defined types (UDTs)**, which allow you to specify the required fields, data types, and any linked credentials or files. To represent dynamic schemas (for example, created by end users from a frontend app), you need to work directly with the API as described in the [following how-to guide](/ssi/schemas/how-to-guides/build-app-for-end-users-to-manage-schemas.md). Prerequisites [Install and configure the SDK](/ssi/sdk/getting-started/installation.md) #### Example: Define a basic credential schema[​](#example-define-a-basic-credential-schema "Direct link to Example: Define a basic credential schema") You can define credential schemas using UDTs, which represent the structure of claims within a credential. For example, a basic `ClaimsModelExample` schema can include `name` and `age` claims: * TypeScript * Java ```ts @VcSchema() class ClaimsModelExample { @VcClaim name?: string; @VcClaim age?: number; } ``` ```java @VcSchema class ClaimsModelExample { String name; int age; } ``` #### Example: Define an advanced credential schema[​](#example-define-an-advanced-credential-schema "Direct link to Example: Define an advanced credential schema") You can define more complex schemas that include different value types, linked credentials, file attachments, and more. ##### Example: Enum values[​](#example-enum-values "Direct link to Example: Enum values") Use the `@VcStringEnumClaim` decorator to define enum values: * TypeScript * Java ```ts @VcSchema() class ClaimsModelExample { @VcStringEnumClaim([ { value: "option1", title: "Option 1" }, { value: "option2", title: "Option 2" }, ]) field1?: "option1" | "option2"; } ``` ```java @VcSchema class ClaimsModelExample { @EnumClaim({ @EnumClaimValue(value = "option1", title = "Option 1"), @EnumClaimValue(value = "option1", title = "Option 1") }) String field1; } ``` ##### Example: Date and date-time values[​](#example-date-and-date-time-values "Direct link to Example: Date and date-time values") To pass date or date-time claim values use two specially defined data types: * `Rfc3339Date` - use this claims type when you want to define a date without time. * `Rfc3339DateTime` - use this claims type when you want to define the date including time (it is equivalent to the JavaScript Date type). For example: * TypeScript * Java ```ts @VcSchema() class ClaimsModelExample { @VcClaim field1?: Rfc3339Date; @VcClaim field2?: Rfc3339DateTime; } ``` ```java @VcSchema class ClaimsModelExample { LocalDate field1; OffsetDateTime field2; } ``` ##### Example: Required values[​](#example-required-values "Direct link to Example: Required values") Use the `@VcNotEmptyClaim` to set the claim as required: * TypeScript * Java ```ts @VcSchema() class ClaimsModelExample { @VcNotEmptyClaim field1!: number; @VcClaim field2?: string; } ``` ```java @VcSchema class ClaimsModelExample { @NotEmpty int field1; String field2; } ``` ##### Example: Array values[​](#example-array-values "Direct link to Example: Array values") If you need to pass an array of primitive or nested struct claims, use the `@VcArrayClaim`. This is used to set the data type of the items in the array claim. For example: * TypeScript * Java ```ts @VcSchema() class ClaimsModelExample { @VcArrayClaim(Number) field1?: number[]; } ``` ```java @VcSchema class ClaimsModelExample { List field1; } ``` ##### Example: Nested structures[​](#example-nested-structures "Direct link to Example: Nested structures") Define a nested structure based on the following example: * TypeScript * Java ```ts @VcSchema() class NestedStruct { @VcArrayClaim(Number) field1?: number[]; } @VcSchema() class ClaimsModelExample { @VcClaim field1?: NestedStruct; } ``` ```java @VcSchema class NestedStruct { List field1; } @VcSchema class ClaimsModelExample { NestedStruct field1; } ``` #### Further reading[​](#further-reading "Direct link to Further reading") You can use UDTs to link credentials to each other and files to credentials. Refer to the following pages for more details: * [Link credentials](/ssi/sdk/linked-data/link-credentials.md) * [Link files](/ssi/sdk/linked-data/link-files.md) #### From schema definition to management[​](#from-schema-definition-to-management "Direct link to From schema definition to management") Defining a credential schema is the first step toward building a trustworthy digital ecosystem. While you can immediately use this schema to [create a draft](/ssi/sdk/credential-lifecycle/create-draft.md) and [issue a credential](/ssi/sdk/credential-lifecycle/issue-credential.md), you need to think about schema publication, versioning, and lifecycle management for a production-ready and interoperable solution. The [Credential Schemas](/ssi/schemas.md) section provides comprehensive documentation on all these topics, empowering you to build future-proof solutions. --- ### Drafts vs credentials #### Drafts[​](#drafts "Direct link to Drafts") A **draft** is a separate, editable resource representing the initial state of a verifiable credential (VC) that can be created, updated, and modified without requiring a signature. The draft state allows you to freely define and refine credential claims before issuing the final, signed VC. Drafts are particularly useful in scenarios such as: * **Multi-step approval processes**: When a credential needs to be reviewed by multiple stakeholders. * **Incomplete data**: When you have partial information and need to update the credential later. Drafts offer flexibility to make changes such as: * Modifying claims (fields and values). * Updating annotations or metadata. * Adjusting labels or human-readable titles. A draft is essential during the credential creation process since it allows for experimentation and adjustment before final issuance. #### Credentials[​](#credentials "Direct link to Credentials") Once a draft is finalized, it can be issued as a VC. A VC can exist in two states: * **Unsigned**: Exported from a *draft* but not yet signed. * **Signed**: Issued and cryptographically signed. The lifecycle of a credential typically follows these steps: 1. [Creating a draft](/ssi/sdk/credential-lifecycle/create-draft.md) 2. [Updating the draft as needed](/ssi/sdk/credential-lifecycle/update-draft.md) 3. [Issuing a draft](/ssi/sdk/credential-lifecycle/issue-credential.md) that does the following under the hood: * Exports the draft as an unsigned VC * Signs the unsigned VC to create a signed VC * Imports the signed VC Once the VC is issued: * It is signed and no longer modifiable. * It can be presented to verifiers for validation. * It can be used as part of a Verifiable Presentation (VP). #### Differences between drafts and issued credentials[​](#differences-between-drafts-and-issued-credentials "Direct link to Differences between drafts and issued credentials") | Feature | Draft | Issued Credential (VC) | | ------------------------- | --------------------------------- | -------------------------------------- | | **Signature Requirement** | Unsigned | Signed using a private key | | **Mutability** | Can be updated and modified | Immutable after issuance | | **Intended Use** | For preparing and refining claims | For sharing, verifying, and validation | #### Further reading[​](#further-reading "Direct link to Further reading") * Learn how to [create a draft](/ssi/sdk/credential-lifecycle/create-draft.md). * Learn how to [update a draft](/ssi/sdk/credential-lifecycle/update-draft.md). * Learn how to [issue a credential](/ssi/sdk/credential-lifecycle/issue-credential.md). --- ### Issue a credential Once a draft is finalized, you can [issue](/ssi/api-reference.md#tag/drafts/operation/DraftIssue) it as a [verifiable credential (VC)](/ssi/overview/core-concepts/verifiable-credentials.md). Issuing a VC finalizes it, making it available for verification by other parties. As mentioned on the [Drafts vs credentials](/ssi/sdk/credential-lifecycle/drafts-vs-credentials.md) page, issuing a draft does the following under the hood: * Exports the draft as an unsigned VC * Signs the unsigned VC to create a signed VC * Imports the signed VC You can also perform each of the steps separately, using the [Export](/ssi/api-reference.md#tag/drafts/operation/DraftExport), [Sign](/ssi/api-reference.md#tag/keys/operation/CredentialSign), and [Import](/ssi/api-reference.md#tag/credentials/operation/CredentialImport) methods for more granular control. Prerequisites * [Install and configure the SDK](/ssi/sdk/getting-started/installation.md) * [Define credential schema](/ssi/sdk/credential-lifecycle/define-credential-schema.md) * [Create a draft](/ssi/sdk/credential-lifecycle/create-draft.md) #### Generate key for signing[​](#generate-key-for-signing "Direct link to Generate key for signing") Before issuing the VC, you need to ensure that you have a public-private key pair to sign the VC. If you have not generated a public-private key pair as part of the [quick start guide](/ssi/sdk/getting-started/quick-start.md), use the example below to generate the key pair with a `P256` curve: * TypeScript * Java ```ts const privateKey = await client.keys.keyGenerate({ data: { type: 'P256', }, }); ``` ```java KeyResource privateKey = client.keys() .keyGenerate(KeyGenerateInput.builder() .data(KeyGenerate.builder().type("P256").build()) .build()); ``` note The Truvity platform supports different types of cryptographic keys. The [Cryptosuites page](/ssi/overview/reference/cryptosuites.md#supported-cryptographic-keys) lists all supported key types and their names. #### Issue credential[​](#issue-credential "Direct link to Issue credential") Call the [`issue` method](/ssi/api-reference.md#tag/drafts/operation/DraftIssue) to issue a `VerifiableCredential` from an existing draft: * TypeScript * Java ```ts const credential = await updatedDraft.issue(privateKey.id); // VerifiableCredentialWithClaims ``` ```java VerifiableCredentialWithClaims credential = updatedDraft.issue(privateKey.getId()); ``` When you have all the necessary information to issue a credential immediately, you can skip creating drafts. The `issue` method on the `VcDecorator` object allows you to do this in one step. The example below takes the previously defined [basic credential schema](/ssi/sdk/credential-lifecycle/define-credential-schema.md), creates the `VcDecorator` instance and issues a credential from the provided claims: * TypeScript * Java ```ts const vcDecoratorInstance = await client.createVcDecorator(ClaimsModelExample); // VcDecorator const issuedCredential = await vcDecoratorInstance.issue( // VerifiableCredentialWithClaims privateKey.id, { claims: { name: "Alice", age: 30 } } ); ``` ```java VcDecorator vcDecoratorInstance = client.vcDecorator(ClaimsModelExample.class); ClaimsModelExample claimsModelData = new ClaimsModelExample(); claimsModelData.setName("Alice"); claimsModelData.setAge(30); VerifiableCredentialWithClaims issuedCredential = vcDecoratorInstance.issue( privateKey.getId(), claimsModelData ); ``` #### Cascade issuance[​](#cascade-issuance "Direct link to Cascade issuance") If a credential has linked draft credentials, when you issue the primary credential, the system also automatically issues all linked draft credentials in the same operation. This lets you prepare a set of related credentials as drafts and issue them together in a single step. For details on linking credentials, see [Link credentials](/ssi/sdk/linked-data/link-credentials.md). #### What happens after issuing?[​](#what-happens-after-issuing "Direct link to What happens after issuing?") Once issued, the credential: * Is signed cryptographically and becomes tamper-evident. * Can no longer be modified. * Is ready to be shared with verifiers for validation. #### Best practices[​](#best-practices "Direct link to Best practices") * **Finalize all data** : Ensure all the necessary data is included before issuing, as credentials cannot be edited once issued. * **Review thoroughly before issuing** : Carefully examine and validate drafts to ensure all fields are accurate and complete, especially in scenarios involving multiple approving parties. #### Further reading[​](#further-reading "Direct link to Further reading") After credential issuance, you can do the following: * [Share issued credential](/ssi/sdk/credential-lifecycle/share-credential-and-presentation.md). * [Verify issued credential](/ssi/sdk/credential-lifecycle/verify-credential.md). --- ### Retrieve credential claims When working with issued verifiable credentials (VCs), you often need to access the data inside them - for example, to display credential details in an app, validate information for business rules, or feed data into automated workflows. The `CredentialClaimValues` method lets you retrieve claim values in a structured, format-independent object. It parses supported credential formats and makes it easier to process credentials from different issuers and ecosystems without dealing with format-specific logic. Prerequisites * [Install and configure the SDK](/ssi/sdk/getting-started/installation.md) * [Define credential schema](/ssi/sdk/credential-lifecycle/define-credential-schema.md) * [Create a draft](/ssi/sdk/credential-lifecycle/create-draft.md) * [Issue a credential](/ssi/sdk/credential-lifecycle/issue-credential.md) #### Retrieve claim values[​](#retrieve-claim-values "Direct link to Retrieve claim values") Call the `CredentialClaimValues` method to read claims from a credential. It returns a standardized object containing all parsed claim values. * TypeScript * Java ```ts const issuedCredentialClaims = await client.credentials.getCredentialClaimValues(issuedCredential.descriptor.id); ``` ```java var issuedCredentialClaims = client.credentials().getCredentialClaimValues(issuedCredential.getId()); ``` note If the credential format is unsupported or the platform cannot parse claims, this method returns an error. You can still access and handle the raw credential blob manually with `CredentialDownload` operation. #### Further reading[​](#further-reading "Direct link to Further reading") * Learn how to [verify credentials](/ssi/sdk/credential-lifecycle/verify-credential.md). * See how to [share credentials and presentations](/ssi/sdk/credential-lifecycle/share-credential-and-presentation.md). --- ### Share a credential or presentation Sharing verifiable credentials and presentations securely is a core feature of the Truvity platform. The platform uses [DIDComm messaging](/ssi/overview/core-concepts/didcomm-messaging.md) for sharing credentials and presentations. Prerequisites * [Install and configure the SDK](/ssi/sdk/getting-started/installation.md) * [Define credential schema](/ssi/sdk/credential-lifecycle/define-credential-schema.md) * [Create a draft](/ssi/sdk/credential-lifecycle/create-draft.md) * [Issue credential](/ssi/sdk/credential-lifecycle/issue-credential.md) #### Share a verifiable credential[​](#share-a-verifiable-credential "Direct link to Share a verifiable credential") To send a DIDComm message containing a verifiable credential (VC), use the `send` method: * TypeScript * Java ```ts await credential.send("targetId", privateKey.id); ``` ```java credential.send("targetId", privateKey.getId()); ``` Where `targetId` is the DID of the receiving party. tip * If you want to send DIDComm messages between two accounts for testing purposes, you can sign up with a different email (or email alias) and use the DID of a new account. - To find the DID of your account, go to the [Admin Panel](https://admin.truvity.com) and click **DID of my tenant**. After you send the DIDComm message with credentials, and/or files, the target wallet automatically receives the message and unpacks the content. #### Share a verifiable presentation[​](#share-a-verifiable-presentation "Direct link to Share a verifiable presentation") [Verifiable presentations](/ssi/overview/core-concepts/verifiable-presentations.md) allow holders to share selected information from their verifiable credentials with a verifier. A presentation can bundle multiple credentials and uses cryptographic proofs to ensure authenticity and integrity. To issue and share a verifiable presentation that contains multiple verifiable credentials, follow the steps below: 1. Initialize the `VpDecorator` instance and use it to create a `VerifiablePresentation`: * TypeScript * Java ```ts const vpDecoratorInstance = await client.createVpDecorator(); // VpDecorator ``` ```java VpDecorator vpDecoratorInstance = client.vpDecorator(); ``` 2. Call the `issue` method to issue a new verifiable presentation and return its representation (a `VerifiablePresentation` instance). * TypeScript * Java ```ts const presentation = await vpDecoratorInstance.issue([credential, credential2], privateKey.id); // VerifiablePresentation ``` ```java VerifiablePresentation presentation = vpDecoratorInstance .issue(List.of(credentialId1, credentialId1), privateKey.getId()); ``` You can pass the following arrays to the `issue` method: * `VerifiableCredential` * `CredentialResource` ids * `CredentialResource` * `UnknownVerifiableCredential` 3. Call the `send` method to send a DIDComm message containing a verifiable presentation: * TypeScript * Java ```ts await presentation.send("targetId", privateKey.id); ``` ```java presentation.send("targetId", privateKey.getId()); ``` Where `targetId` is the DID of the receiving party. After you send the DIDComm message with the presentation, credentials, and/or files, the target wallet automatically receives the message and unpacks the content. #### Configure transitive closure[​](#configure-transitive-closure "Direct link to Configure transitive closure") By default, the system retrieves all directly referenced resources as well as any linked resources recursively. If you need to control this behavior, you can use the `disable_transitive_closure` flag: * TypeScript * Java ```ts await client.didcommMessages.didCommMessageSend({ data: { to: "targetId", keyId: privateKey.id, credentials: [credential.descriptor.id], disableTransitiveClosure: true, }, }); ``` ```java client.didcommMessages() .didCommMessageSend(DidCommMessageSendRequest.builder() .data(DidCommMessageSend.builder() .keyId(privateKey.getId()) .to("recipientDID") .credentials(List.of(credential.descriptor().id())) .disableTransitiveClosure(true) .build()) .build()); ``` ##### About `disable_transitive_closure`[​](#about-disable_transitive_closure "Direct link to about-disable_transitive_closure") The `disable_transitive_closure` flag determines whether the system retrieves only explicitly referenced resources or follows links to related resources: * **`true`** - Only explicitly referenced resources (credentials, files, presentations) are retrieved. Linked resources are ignored. * **`false`** (default) - The system performs transitive traversal, retrieving all directly referenced resources and any linked resources recursively. This flag applies to resources such as credentials, files, and presentations, influencing how dependencies are resolved during message processing. --- ### Update a draft Drafts can be updated before they are finalized and issued. Updating a draft is useful when new data becomes available or when changes need to be made based on feedback. Prerequisites * [Install and configure the SDK](/ssi/sdk/getting-started/installation.md) * [Define credential schema](/ssi/sdk/credential-lifecycle/define-credential-schema.md) * [Create a draft](/ssi/sdk/credential-lifecycle/create-draft.md) #### Example: Update a draft[​](#example-update-a-draft "Direct link to Example: Update a draft") To update claims values, labels, annotations, and metadata (if available) of a draft, call the `update` method that returns a promise. This promise resolves to another instance of the updated `Draft` (the most up-to-date version of the draft with the latest revision): * TypeScript * Java ```ts const updatedDraft = await createdDraft.update({ claims: { field1: "Field 1 claim value", }, }); ``` ```java ClaimsModelExample claimsModelData = new ClaimsModelExample(); claimsModelData.setField1(""Field 1 claim value""); var updatedDraft = createdDraft.update(claimsModelData); ``` #### Further reading[​](#further-reading "Direct link to Further reading") After updating the draft, you can do the following: * [Issue credential](/ssi/sdk/credential-lifecycle/issue-credential.md). --- ### User-defined types (UDTs) User-defined types (UDTs) are a core component of the Truvity SDK, enabling developers to define the structure and semantics of Verifiable Credentials (VCs) in a strongly typed and idiomatic way for their chosen programming language. #### What is a UDT?[​](#what-is-a-udt "Direct link to What is a UDT?") A **user-defined type (UDT)** is a custom data model that represents a claims within a credential. UDTs allow for flexibility in defining the structure of credential claims, ensuring that each credential follows a specific schema. As a developer, you use UDTs as the source of truth for creating schemas, which are then used by the Truvity platform to ensure the integrity, verifiability, and interoperability of the verifiable credentials you issue. #### Benefits of UDTs[​](#benefits-of-udts "Direct link to Benefits of UDTs") UDTs enable enhanced type safety and ensure that errors related to data types are caught during the credential lifecycle, including creation, updating, issuance, and validation. These types are particularly useful when credentials need to be tailored for different use cases such as personal identification, birth certificates, or other types of documents. Using UDTs simplifies development and ensures that: * Credential claims are well-structured. * Schema validation is enforced. * Credentials can be linked or nested, improving interoperability. #### Further reading[​](#further-reading "Direct link to Further reading") * [Define credential schemas](/ssi/sdk/credential-lifecycle/define-credential-schema.md). --- ### Verify a credential Verifying a verifiable credential ensures that the data it contains is authentic and has not been tampered with. The verification process checks the cryptographic proof attached to the credential, validating its issuer and claims. Prerequisites * [Install and configure the SDK](/ssi/sdk/getting-started/installation.md) * [Define credential schema](/ssi/sdk/credential-lifecycle/define-credential-schema.md) * [Create a draft](/ssi/sdk/credential-lifecycle/create-draft.md) * [Issue credential](/ssi/sdk/credential-lifecycle/issue-credential.md) #### Example: Verify credential[​](#example-verify-credential "Direct link to Example: Verify credential") To verify a credential, use the `verify` method: * TypeScript * Java ```ts const verificationResult = await credential.verify(); ``` ```java var verificationResult = credential.verify(); ``` #### Further reading[​](#further-reading "Direct link to Further reading") * [Share issued credential](/ssi/sdk/credential-lifecycle/share-credential-and-presentation.md). --- ### Installation and configuration This guide helps you install the Truvity API client and ensures your environment meets the required system specifications. #### System requirements[​](#system-requirements "Direct link to System requirements") Before you install the Truvity SDK, make sure your system meets these requirements: * TypeScript * Java - **Node.js version 16.16 or later**. Download it from the official [Node.js website](https://nodejs.org/). - **Operating systems**: macOS, Windows, or Linux * **Java version 11 or later**. Download it from the official [Java website](https://www.java.com/). * **Operating systems**: macOS, Windows, or Linux Ensure that your environment meets these requirements to avoid compatibility issues. #### Obtain API key[​](#obtain-api-key "Direct link to Obtain API key") Before using the API, you need to obtain the API key to authenticate calls. Follow the [Create API keys](/ssi/overview/security/create-api-keys.md) guide to create a new API key. #### Install the SDK[​](#install-the-sdk "Direct link to Install the SDK") The SDK installation instructions depend on the SDK language you want to use. * TypeScript * Java Use the `npm` command to install the TypeScript SDK: ```bash npm install @truvity/sdk ``` Package link on [npm](https://www.npmjs.com/package/@truvity/sdk). **Maven Dependency:** To include the Truvity SDK as a dependency in your Maven project, add the following to your `pom.xml`. Make sure to replace the `` placeholder with the most recent version available from the [Maven Central Repository](https://search.maven.org/artifact/com.truvity/sdk). ```xml com.truvity sdk ``` **Gradle Dependency:** To add the Truvity SDK in Gradle, include the following line in your `build.gradle` file. Again, replace `` with the latest version from the [Maven Central Repository](https://search.maven.org/artifact/com.truvity/sdk). ```groovy implementation group: 'com.truvity', name: 'sdk', version: '' ``` #### Create the API client[​](#create-the-api-client "Direct link to Create the API client") To begin using the API, you first need to create a new API client. Use the following code to set up the client: * TypeScript * Java ```ts import { TruvityClient } from "@truvity/sdk"; const client = new TruvityClient({ apiKey: "YOUR_API_KEY", }); ``` Where `YOUR_API_KEY` is the API key you obtained in the previous step. ```java import com.truvity.api.TruvityApiExtendedClient; import com.truvity.api.TruvityApiExtendedClientBuilder; static TruvityApiExtendedClientBuilder builder = new TruvityApiExtendedClientBuilder() .apiKey(System.getenv("YOUR_API_KEY")); static TruvityApiExtendedClient client = builder.build(); ``` Where `YOUR_API_KEY` is the API key you obtained in the previous step. This code initializes a new client for the Truvity API, which makes API calls to Truvity Cloud. #### Make API calls[​](#make-api-calls "Direct link to Make API calls") Once you set up the API client, use API methods to perform actions with the [available API operations](/ssi/api-reference.md). For example, to [create a new API key](/ssi/api-reference.md#tag/api-keys/operation/ApiKeyCreate), use the following code: * TypeScript * Java ```ts await client.apiKeys.apiKeyCreate({ idempotencyKey: "7da7a728-f910-11e6-942a-68f728c1ba70", body: {} }); ``` ```java client.apiKeys().apiKeyCreate(ApiKeyCreateRequest.builder() .body(ApiKeyInput.builder().build()) .idempotencyKey("7da7a728-f910-11e6-942a-68f728c1ba70") .build()); ``` #### Next steps[​](#next-steps "Direct link to Next steps") Now that you have installed the SDK, you are ready to start building your first app using the Truvity SDK. Here are some recommended next steps to help you get started: ##### 1. Explore the quick start guide[​](#1-explore-the-quick-start-guide "Direct link to 1. Explore the quick start guide") The [Quick start](/ssi/sdk/getting-started/quick-start.md) guide is the best place to begin after installing the SDK. It demonstrates key operations such as issuing credentials and interacting with wallet data. ##### 2. Review API documentation[​](#2-review-api-documentation "Direct link to 2. Review API documentation") For detailed information on the available API endpoints, parameters, and response formats, check out the [API reference](/ssi/api-reference.md). The API documentation provides code samples in multiple languages to help you integrate the SDK into your app seamlessly. ##### 3. Start building[​](#3-start-building "Direct link to 3. Start building") Once you gone through the **Quick Start Guide**, you are ready to begin building your first app. * Explore the [Credential lifecycle](/ssi/sdk/credential-lifecycle/drafts-vs-credentials.md) section and go through step-by-step guides through the process of creating, issuing, sharing and verifying credentials and presentations. ##### 4. Explore advanced features[​](#4-explore-advanced-features "Direct link to 4. Explore advanced features") Once you are comfortable with the basics, you can dive into more advanced features of the SDK, such as: * [**Building end-to-end credential lifecycle**](/ssi/sdk/credential-lifecycle/create-draft.md): Learn how to cover the full credential lifecycle from creating a credential to sharing it with the verifier. * [**Working with linked data**](/ssi/sdk/linked-data/link-credentials.md): Learn how to link credentials to each other and files to credentials. * [**Managing credential data**](/ssi/sdk/manage-data/model-with-labels.md): Explore how to model credential data with labels, use faceted search to retrieve results, and view credential history. #### Further reading[​](#further-reading "Direct link to Further reading") * [Authentication and Security Considerations](/ssi/overview/security.md) * [API Reference Documentation](/ssi/api-reference.md) --- ### Quick start guide This guide walks you through the process of creating and verifying a verifiable credential (VC) using the Truvity SDK. You utilize [user-defined types (UDTs)](/ssi/sdk/credential-lifecycle/user-defined-types.md) to represent the credential claims schema, enhancing type safety and simplifying the credential lifecycle. #### Prerequisites[​](#prerequisites "Direct link to Prerequisites") Before you begin, make sure you have the following: * Installed and configured Truvity SDK. If you do not have the installed SDK, follow the [Installation](/ssi/sdk/getting-started/installation.md) guide. * A basic understanding of **Self-Sovereign Identity (SSI)** concepts, such as Decentralized Identifiers (DIDs), verifiable credentials (VCs), and verifiable presentations (VPs). For more information, refer to the [Core Concepts](/ssi/overview/core-concepts/verifiable-credentials.md) section. #### Step 1: Define a simple credential type[​](#step-1-define-a-simple-credential-type "Direct link to Step 1: Define a simple credential type") Begin by defining a simple credential type using UDTs. This credential type contains two required claims: `name` and `age`. * TypeScript * Java ```ts import { Truvity, VcSchema, VcClaim } from '@truvity/sdk'; // Define a simple credential type using UDT @VcSchema() class SimpleCredential { @VcClaim name?: string; @VcClaim age?: number; } ``` ```java import com.truvity.api.documents.annotations.VcSchema; @VcSchema class SimpleCredential { String name; int age; } ``` The `@VcClaim` decorator marks the fields as claims in the credential. #### Step 2: Generate a key for signing[​](#step-2-generate-a-key-for-signing "Direct link to Step 2: Generate a key for signing") To issue a credential, you first need to generate a cryptographic key. The following example shows how generate a `ED25519` key type. * TypeScript * Java ```ts const key = await client.keys.keyGenerate({ data: { type: 'ED25519' } }); ``` ```java KeyResource key = client.keys() .keyGenerate(KeyGenerateInput.builder() .data(KeyGenerate.builder().type("ED25519").build()) .build()); ``` You use this key to sign the credential later in the process. #### Step 3: Create a draft[​](#step-3-create-a-draft "Direct link to Step 3: Create a draft") Now, create a draft using the `SimpleCredential` UDT that you defined in **Step 1**. This draft includes claims (`name` and `age`) to embed in the credential. info *Draft* is a concept introduced by Truvity that represents the initial state of credential's content. To learn more about drafts, check the [Drafts vs credentials](/ssi/sdk/credential-lifecycle/drafts-vs-credentials.md) page. * TypeScript * Java ```ts const simpleCredDecorator = client.createVcDecorator(SimpleCredential); const draft = await simpleCredDecorator.create({ claims: { name: "Alice", age: 30 } }); ``` ```java VcDecorator simpleCredDecorator = client.vcDecorator(SimpleCredential.class); SimpleCredential simpleCredentialData = new SimpleCredential(); simpleCredentialData.name = "Alice"; simpleCredentialData.age = 30; DraftCredentialWithClaims draft = simpleCredDecorator.create(simpleCredentialData); ``` In this step, the credential is not yet issued or signed - it is just a draft that contains the claims data. #### Step 4: Issue the credential[​](#step-4-issue-the-credential "Direct link to Step 4: Issue the credential") Next, issue the credential by signing it with the previously generated key. This transforms the draft into a verifiable credential (VC). * TypeScript * Java ```ts const issuedVC = await draft.issue(key.id); ``` ```java var issuedVC = draft.issue(key.getId()); ``` The issued credential is now cryptographically signed and can be shared with other parties. #### Step 5: Verify the credential[​](#step-5-verify-the-credential "Direct link to Step 5: Verify the credential") Finally, verify the authenticity of the issued credential. Verification ensures that the credential has not been tampered with and that it was signed by a valid key. * TypeScript * Java ```ts const verificationResult = await issuedVC.verify(); console.log("Verification result:", verificationResult.verified); ``` ```java var verificationResult = issuedVC.verify(); System.out.println(verificationResult.verified()); ``` The `verify()` function checks the integrity and validity of the credential, and the result is printed to the console. #### Putting it all together[​](#putting-it-all-together "Direct link to Putting it all together") Now that each step is covered, here is the full code that puts everything together. This code defines a credential, generates a key, creates a draft, issues the credential, and finally verifies it. * TypeScript * Java ```ts import { TruvityClient, VcSchema, VcClaim } from '@truvity/sdk'; // Define a simple credential type using UDT @VcSchema() class SimpleCredential { @VcClaim name!: string; @VcClaim age!: number; } async function createAndVerifyVC() { // Initialize the SDK client const client = new Truvity.TruvityClient({ environment: "https://api.truvity.com", apiKey: "YOUR_API_KEY", }); // Generate a key for signing const key = await client.keys.keyGenerate({ data: { type: 'ED25519' } }); // Create a credential decorator const simpleCredDecorator = client.createVcDecorator(SimpleCredential); // Create a draft const draft = await simpleCredDecorator.create({ claims: { name: "Alice", age: 30 } }); // Issue the credential const issuedVC = await draft.issue(key.id); // Verify the credential const verificationResult = await issuedVC.verify(); console.log("Verification result:", verificationResult.verified); } createAndVerifyVC(); ``` ```java // Define a simple credential type using UDT @VcSchema class SimpleCredential { String name; int age; } void createAndVerifyVC() { // Initialize the SDK client TruvityApiExtendedClient client = new TruvityApiExtendedClientBuilder() .environment(Environment.custom("https://api.truvity.com")) .apiKey(System.getenv("YOUR_API_KEY")).build(); // Generate a key for signing ResourceKeyPublic key = client.keys() .keyGenerate(KeyGenerateRequest.builder() .data(KeyGenerate.builder().type(KeyGenerateType.ED_25519).build()) .build()); // Create a credential decorator VcDecorator simpleCredDecorator = client.vcDecorator(SimpleCredential.class); SimpleCredential simpleCredentialData = new SimpleCredential(); simpleCredentialData.name = "Alice"; simpleCredentialData.age = 30; // Create a draft var draft = simpleCredDecorator.create(simpleCredentialData); // Issue the credential var issuedVC = draft.issue(key.getId()); // Verify the credential var verificationResult = issuedVC.verify(); System.out.println(verificationResult.verified()); } ``` Congratulations! You have just issued your first Truvity-powered verifiable credential and is now ready to explore more topics on working with the SDK. #### Further reading[​](#further-reading "Direct link to Further reading") * Cover the full [credential lifecycle](/ssi/sdk/credential-lifecycle/drafts-vs-credentials.md) from creating a credential to sharing it with the verifier. * Learn how to [link credentials to each other and files to credentials](/ssi/sdk/linked-data/link-credentials.md). * Explore how to [manage credential data](/ssi/sdk/manage-data/model-with-labels.md) by modeling credential data with labels, using faceted search to retrieve results, and viewing credential history. --- ### Create web invitation-based custodial B2B wallets #### Overview[​](#overview "Direct link to Overview") This guide walks you through setting up invitation-based custodial wallets for business-to-business (B2B) scenarios on a web platform provided by a wallet provider. In a B2B context, multiple users from the same organization may need access to a shared wallet with role-based permissions. For simplicity, the guide refers to this as a “wallet,” though in B2B it often functions more like credential storage. **Business context:** While the term "wallet" is intuitive in retail contexts where individuals manage their own assets, B2B environments involve shared ownership and access. For businesses, this "wallet" is more of a credential repository with varying access levels for different departments or roles. This solution supports secure collaboration and compliance within organizations. Prerequisites * [Install and configure the SDK](/ssi/sdk/getting-started/installation.md) * [Understanding of decentralized identifiers (DIDs), verifiable credentials (VCs), and DIDComm messaging](/ssi/overview/core-concepts/decentralized-identifiers.md) #### Step 1: Set up a custodial wallet for an organization[​](#step-1-set-up-a-custodial-wallet-for-an-organization "Direct link to Step 1: Set up a custodial wallet for an organization") **Goal:** Set up an organization or department with a dedicated email address and automatically create a tenant, credential storage, and DID under the hood. **Business context:** Why invitation-based custodial wallets?\*\* Requiring each organization or department to use a dedicated email (for example, `compliance@bank-abc.com` or `back-office@bank-abc.com`) simplifies the onboarding process. It ensures that the wallet provider handles the creation of tenants and the generation of DIDs, eliminating the need for complex manual setup. This design supports operational scalability while maintaining control over wallet creation. ##### Instructions[​](#instructions "Direct link to Instructions") ###### Request account provisioning[​](#request-account-provisioning "Direct link to Request account provisioning") To set up wallets for your organization or departments, contact . Each organization or department that needs a wallet should be registered with a separate email address. For example: * **Compliance Department**: `compliance@bank-abc.com` * **Back Office Department**: `back-office@bank-abc.com` ###### Automatic creation of tenant and credential storage[​](#automatic-creation-of-tenant-and-credential-storage "Direct link to Automatic creation of tenant and credential storage") After your accounts are provisioned, the platform automatically creates the following under the hood: * A tenant (representing the department). * A credential storage associated with that tenant. * A Decentralized Identifier (DID) assigned to the tenant. Assigning a unique DID to each organization or department provides a verifiable digital identity, which ensures that any credentials issued or shared are traceable back to a legitimate entity. This structure enhances trust in credential exchanges. #### Step 2: Organize storage data using labels[​](#step-2-organize-storage-data-using-labels "Direct link to Step 2: Organize storage data using labels") **Goal:** Structure wallet data with labels to control access and provide fine-grained resource management. In the context of this guide, you use labels to separate access to resources within one department based on the roles accessing these resources. note As mentioned at the beginning of this guide, the assumption is that each department has its own tenant and tenant users are not able to access resources of another tenant, therefore this guide does not use labels to separate access to resources based on the department. **Business context:** **Why use labels?** In a large organization, different roles even within a single department (for example, Compliance Analyst, Anti-Money Laundering (AML) Officer, KYC (Know Your Customer) Specialist) require access to different sets of credentials. Labels provide a flexible way to manually or automatically categorize and manage credentials and other resources based on various attributes, such as role or set of customers. This simplifies managing complex data and ensures that the right credentials are accessible to the right people. ##### Instructions[​](#instructions-1 "Direct link to Instructions") ###### Attach labels to credentials[​](#attach-labels-to-credentials "Direct link to Attach labels to credentials") When issuing or receiving credentials, you can attach appropriate labels to the [resources](/ssi/overview/reference/rest-resources-operations.md) to use them later on for access control. Take the following example: only AML officers need to be able to see certain [DIDComm messages](/ssi/overview/core-concepts/didcomm-messaging.md) that were sent to other parties. To achieve this, attach the `role` label with the `aml-officer` value to the DIDComm message when sending it: * TypeScript * Java ```ts await client.didcommMessages.didCommMessageSend({ data: { to: 'recipientDid', keyId: 'key_id' }, labels: { role: 'aml-officer' } }); ``` ```java client.didcommMessages() .didCommMessageSend(DidCommMessageSendInput.builder() .data(DidCommMessageSend.builder() .to("recipientDid") .keyId("key_ud") .build()) .labels(Map.of("role", "aml-officer")) .build()); ``` info * To learn more about sharing credentials and presentations using DIDComm messaging, refer to the [following page](/ssi/sdk/credential-lifecycle/share-credential-and-presentation.md). * To learn more about adding labels to other REST resources, refer to the [following page](/ssi/sdk/manage-data/model-with-labels.md) Labels act as a form of metadata that allows for granular control over who can view or act upon resources. This approach supports organizational policies around data segregation and compliance, making it easier to audit access and ensure that only authorized individuals handle sensitive data. #### Step 3: Implement faceted search for resource access[​](#step-3-implement-faceted-search-for-resource-access "Direct link to Step 3: Implement faceted search for resource access") **Goal:** Enable users to search for and access labeled resources based on their role using faceted search. **Business context:** **Why faceted search?** In B2B scenarios, where the organization may store numerous resources, it is essential for users to quickly locate the resources they only have access to and the credentials they need. Faceted search allows users to filter resources based on various criteria (for example, role), improving security and efficiency in credential management. ##### Instructions[​](#instructions-2 "Direct link to Instructions") ###### Use faceted search to search for resources[​](#use-faceted-search-to-search-for-resources "Direct link to Use faceted search to search for resources") You can use faceted search to query the resource database based on labels. To expand on the example from the previous step, search for all DIDComm messages marked with the `role` label and the `aml-officer` label value: * TypeScript * Java ```ts const searchResult = await client.didcommMessages.didcommMessageSearch({ filter: [ { labels: [ { operator: 'EQUAL', key: 'role', value: 'aml-officer', }, ], }, ], }); ``` ```java ListDidCommMessage searchResult = client.didcommMessages() .didcommMessageSearch(DidcommMessageSearchRequest.builder() .filter(List.of(DidcommMessageFilter.builder() .labels(List.of( DidcommMessageFilterLabelsItem.equal(KeyEqualLabelKeyLabelValue.builder() .key("role") .value("aml-officer") .build()))) .build())) .build()); ``` In the preceding example, faceted search serves two needs: 1. It improves security by separating access to resources based on labels. 2. It improves operational efficiency by allowing users to filter large datasets of resources to quickly find what they need. This is especially useful in large organizations with multiple roles, where the number or credentials and other resources might be big. info If you want to learn more about using faceted search, refer to the [following page](/ssi/sdk/manage-data/use-faceted-search.md). #### Step 4: Share credentials using DIDComm Messaging[​](#step-4-share-credentials-using-didcomm-messaging "Direct link to Step 4: Share credentials using DIDComm Messaging") **Goal:** Enable secure credential sharing between wallets while storing a verifiable record of the transaction (message) between two parties. **Business context:** **Why use DIDComm for credential sharing?** In B2B scenarios, logging transactions is critical for regulatory compliance, dispute resolution, and ensuring accountability between parties. DIDComm messaging not only encrypts the credential exchange but also ensures that the transaction itself is logged, which can be used for auditing purposes. ##### Instructions[​](#instructions-3 "Direct link to Instructions") ###### Send credentials via DIDComm[​](#send-credentials-via-didcomm "Direct link to Send credentials via DIDComm") Create a DIDComm message to send one or more credentials (as a verifiable presentation) to another wallet. info If you want to learn more about issuing credentials, refer to the [following page](/ssi/sdk/credential-lifecycle/issue-credential.md). In the example below, the DIDComm message contains one verifiable credential. * TypeScript * Java ```ts await credential.send('recipientDid', key.id); ``` ```java credential.send("recipientDid", privateKey.getId()); ``` info If you want to learn more about sending verifiable credentials and presentations using DIDComm Messaging, refer to the [following page](/ssi/sdk/credential-lifecycle/share-credential-and-presentation.md). ###### Get notified of received DIDComm messages[​](#get-notified-of-received-didcomm-messages "Direct link to Get notified of received DIDComm messages") Now move to the receiver’s wallet. To enable user notification, check for new DIDComm messages received by the wallet so the user can process them. Although the Truvity SDK does not provide built-in notification capabilities, it is possible to create a cron job that calls the faceted search to find all DIDComm messages received within a specified time period, such as the last 5 minutes or since the last cron update. * TypeScript * Java ```ts const { id: myDid } = await client.dids.didDocumentSelfGet(); const fiveMinAgo = new Date(Date.now() - 5 * 60 * 1000); const filterResult = await client.didcommMessages.didcommMessageSearch({ filter: [ { data: { to: { operator: 'EQUAL', value: myDid, }, }, createdAt: { operator: 'GREATER_THAN_OR_EQUAL', value: fiveMinAgo, }, }, ], }); ``` ```java String myDid = client.dids().didDocumentSelfGet().getId(); OffsetDateTime fiveMinAgo = OffsetDateTime.now().minusMinutes(5); ListDidCommMessage filterResult = client.didcommMessages().didcommMessageSearch(DidcommMessageSearchRequest.builder() .filter(List.of( DidcommMessageFilter.builder() .data(DidcommMessageFilterData.builder().to(DidcommMessageFilterDataTo.equal(EqualDid.builder().value(myDid).build())).build()) .createdAt(DidcommMessageFilterCreatedAt.greaterThanOrEqual(TimestampGreaterThanOrEqual.builder().value(fiveMinAgo).build())) .build() )) .build()); ``` #### Step 5: Audit credential transactions[​](#step-5-audit-credential-transactions "Direct link to Step 5: Audit credential transactions") **Goal:** Allow auditing of credential issuance and sharing for accountability and compliance. important While the Truvity platform does not provide a full end-to-end auditing solution, you can create the audit log using available SDK methods and APIs. **Business context:** **Why audit credential transactions?** In highly regulated industries, such as finance, healthcare, or government, businesses must be able to prove the integrity of their credentialing processes. Auditing provides a trail that can be reviewed for compliance purposes, ensuring that only authorized entities issued and accessed credentials. ##### Instructions[​](#instructions-4 "Direct link to Instructions") ###### Track credential issuance[​](#track-credential-issuance "Direct link to Track credential issuance") Read the latest version of the credential (by providing it's UUID) to fetch issuance details of a credential such as the DID of the issuer and the creation date. * TypeScript * Java ```ts const latestVersion = await client.credentials.credentialLatest("497f6eca-6276-4993-bfeb-53cbbbba6f08"); ``` ```java ResourceCredential latestVersion = client.credentials().credentialLatest("497f6eca-6276-4993-bfeb-53cbbbba6f08"); ``` ###### Monitor credential sharing[​](#monitor-credential-sharing "Direct link to Monitor credential sharing") To monitor sharing of credentials via DIDComm messaging, you can get the latest version of the DIDComm message. Use the [`DidcommMessageLatest`](/ssi/api-reference.md#tag/didcomm-messages/operation/DidcommMessageLatest) API method to retrieve the details of a previously sent DIDComm message. The call returns the details of the message including verifiable credentials and presentations that can be added to the audit log. * TypeScript * Java ```ts const result = await client.didcommMessages.didcommMessageLatest("497f6eca-6276-4993-bfeb-53cbbbba6f08"); ``` ```java ResourceDidCommMessage result = client.didcommMessages().didcommMessageLatest("497f6eca-6276-4993-bfeb-53cbbbba6f08"); ``` #### Conclusion[​](#conclusion "Direct link to Conclusion") In this guide, you learned how to set up and manage invitation-based custodial B2B wallets, share credentials securely via DIDComm messaging, and, most importantly, log every credential exchange transaction to ensure compliance, accountability, and trust in business-to-business interactions. The guide covered: 1. **Account Provisioning and Credential Storage Creation**: Organizations and departments are set up through Truvity, which automatically creates a tenant, credential storage, and DID for each department, streamlining the onboarding process. 2. **Data Organization with Labels**: Using labels to organize data inside single credential storage. 3. **Using Search to Retrieve Relevant Data**: Using faceted search to retrieve resources. 4. **Credential Sharing and Transaction Logging**: Using DIDComm messaging to securely exchange credentials between wallets, while also logging every transaction to provide verifiable proof of the exchange. This feature is critical for maintaining regulatory compliance, resolving disputes, and establishing trust between business partners. --- ### Link credentials In many cases, it is necessary to create relationships between different credentials. For example, you might link a diploma credential to a professional license, or a national ID to a work visa. The Truvity SDK allows you to link credentials together to form a hierarchy of related data. Prerequisites * [Install and configure the SDK](/ssi/sdk/getting-started/installation.md) * [Define credential schema](/ssi/sdk/credential-lifecycle/define-credential-schema.md) * [Create a draft](/ssi/sdk/credential-lifecycle/create-draft.md) #### Why link credentials?[​](#why-link-credentials "Direct link to Why link credentials?") Linking credentials provides several benefits: * **Data integrity**: Maintain the integrity of related credentials, ensuring they are connected in a meaningful way. * **Hierarchical relationships**: Create relationships between credentials, such as educational qualifications and work history, to form a complete identity profile. * **Simplified verification**: Verifiers can easily check related credentials in one verification request. #### Example: Link credential[​](#example-link-credential "Direct link to Example: Link credential") To link one credential to another, use the `LinkedCredential` custom claim type available as part of the [user-defined types (UDTs)](/ssi/sdk/credential-lifecycle/user-defined-types.md): * TypeScript * Java ```ts @VcSchema() class Passport { @VcNotEmptyClaim name!: string; } @VcSchema() class ClaimsModelExample { @VcNotEmptyClaim passport!: LinkedCredential; } const key = await client.keys.keyGenerate({ data: { type: 'P256', }, }); const passport = client.createVcDecorator(Passport); const passportVc = await passport.issue(key.id, { claims: { name: "John Smith" } }); const claimsModelExample = client.createVcDecorator(ClaimsModelExample); const claimsModelExampleVc = await claimsModelExample.issue(key.id, { claims: { passport: passportVc } }); const claimsModelExampleClaims = await claimsModelExampleVc.getClaims(); const linkedPassport = await claimsModelExampleClaims.passport.dereferenceAs(Passport); const linkedPassportClaims = await linkedPassport.getClaims(); linkedPassportClaims.name; // "John Smith" ``` ```java @VcSchema() class Passport { @NotEmpty private String name; Passport(String name) { this.name = name; } } @VcSchema() class ClaimsModelExample { @NotEmpty private LinkedCredential passport; ClaimsModelExample(LinkedCredential passport) { this.passport = passport; } } ResourceKeyPublic key = client.keys() .keyGenerate(KeyGenerateRequest.builder() .data(KeyGenerate.builder().type(KeyGenerateType.P_256).build()) .build()); VcDecorator passport = client.vcDecorator(Passport.class); VerifiableCredentialWithClaims passportVc = passport.issue( key.getId(), new Passport("John Smith") ); VcDecorator claimsModelExample = client.vcDecorator(ClaimsModelExample.class); VerifiableCredentialWithClaims claimsModelExampleVc = claimsModelExample.issue( key.getId(), new ClaimsModelExample(passportVc.toLinkedCredential()) ); LinkedCredential passportLinkedCredential = claimsModelExampleVc.getClaims().passport; VerifiableCredentialWithClaims linkedPassportVc = passportLinkedCredential.dereferenceVerifiableCredential(); linkedPassportVc.getClaims().name; // "John Smith" ``` #### Example: Link draft credentials[​](#example-link-draft-credentials "Direct link to Example: Link draft credentials") You can link a draft credential to an issued credential or to another draft credential. When you issue any credential in the linked set, the system also automatically issues all linked draft credentials. This lets you define relationships between credentials while they are still drafts, and issue them together in a single operation. * TypeScript * Java ```ts @VcSchema() class Passport { @VcNotEmptyClaim name!: string; } @VcSchema() class ClaimsModelExample { @VcNotEmptyClaim passport!: LinkedCredential; } const key = await client.keys.keyGenerate({ data: { type: 'P256', }, }); const passport = client.createVcDecorator(Passport); const passportDraft = await passport.create({ claims: { name: "John Smith" } }); const claimsModelExample = client.createVcDecorator(ClaimsModelExample); const claimsModelExampleDraft = await claimsModelExample.create({ claims: { passport: passportDraft } }); await passportDraft.update({claims: { name: "Tom Smith" }}); const claimsModelExampleVc = await claimsModelExampleDraft.issue(key.id); const claimsModelExampleClaims = await claimsModelExampleVc.getClaims(); const linkedPassport = await claimsModelExampleClaims.passport.dereferenceAs(Passport); const linkedPassportClaims = await linkedPassport.getClaims(); linkedPassportClaims.name; // "Tom Smith" ``` ```java @VcSchema class Passport { @NotEmpty private String name; Passport(String name) { this.name = name; } } @VcSchema class ClaimsModelExample { @NotEmpty private LinkedCredential passport; ClaimsModelExample(LinkedCredential passport) { this.passport = passport; } } ResourceKeyPublic key = client.keys() .keyGenerate(KeyGenerateRequest.builder() .data(KeyGenerate.builder().type(KeyGenerateType.P_256).build()) .build()); VcDecorator passport = client.vcDecorator(Passport.class); DraftCredentialWithClaims passportDraft = passport.create(new Passport("John Smith")); VcDecorator claimsModelExample = client.vcDecorator(ClaimsModelExample.class); DraftCredentialWithClaims claimsModelExampleDraft = claimsModelExample.create(new ClaimsModelExample(passportDraft.toLinkedCredential())); passportDraft.update(new Passport("Tom Smith")); VerifiableCredentialWithClaims claimsModelExampleVc = claimsModelExampleDraft.issue(key.getId()); LinkedCredential passportLinkedCredential = claimsModelExampleVc.getClaims().passport; VerifiableCredentialWithClaims linkedPassportVc = passportLinkedCredential.dereferenceVerifiableCredential(); linkedPassportVc.getClaims().name; // "Tom Smith" ``` #### Example: Link multiple credential types[​](#example-link-multiple-credential-types "Direct link to Example: Link multiple credential types") A single claim is able to support multiple different types of linked credentials (one at a time). This can be useful when more than one type of document can be used for the same purpose. For example, different certificates, like birth or marriage certificates, can often fulfill the same role or, as another example, passports of different nationalities. * TypeScript * Java There are two approaches to linking multiple credential types on a single claim: * Listing the different types, such as `LinkedCredential`, like the example below. This approach would be used in cases where the set of different linked credential types is statically known. * Using the `LinkedCredential` type. This approach would be used when you're handling an arbitrary set of types that is not statically known. Both approaches provide the same programming interface. The first approach, listing the types, provides better static type checking. ```ts @VcSchema() class PassportNL { @VcNotEmptyClaim nameNL!: string; } @VcSchema() class PassportDE { @VcNotEmptyClaim nameDE!: string; } @VcSchema() class ClaimsModelExample { @VcNotEmptyClaim passport!: LinkedCredential; } const key = await client.keys.keyGenerate({ data: { type: 'P256', }, }); const passport = client.createVcDecorator(PassportNL); const passportVc = await passport.issue(key.id, { claims: { nameNL: "John Smith" } }); const claimsModelExample = client.createVcDecorator(ClaimsModelExample); const claimsModelExampleVc = await claimsModelExample.issue(key.id, { claims: { passport: passportVc } }); const claimsModelExampleClaims = await claimsModelExampleVc.getClaims(); const passportLinkedCredential = await claimsModelExampleClaims.passport.dereference(); if (await passportLinkedCredential.canMap(PassportNL)) { const linkedPassport = await passportLinkedCredential.map(PassportNL); const linkedPassportClaims = await linkedPassport.getClaims(); linkedPassportClaims.nameNL; // "John Smith" } else { const linkedPassport = await passportLinkedCredential.map(PassportDE); const linkedPassportClaims = await linkedPassport.getClaims(); linkedPassportClaims.nameDE; } ``` ```java @VcSchema class PassportNL { @NotEmpty private String nameNL; PassportNL(String name) { this.nameNL = name; } } @VcSchema class PassportDE { @NotEmpty private String nameDE; PassportDE(String name) { this.nameDE = name; } } @VcSchema class ClaimsModelExample { @NotEmpty private LinkedCredentialUnknown passport; ClaimsModelExample(LinkedCredentialUnknown passport) { this.passport = passport; } } ResourceKeyPublic key = client.keys() .keyGenerate(KeyGenerateRequest.builder() .data(KeyGenerate.builder().type(KeyGenerateType.P_256).build()) .build()); VcDecorator passport = client.vcDecorator(PassportNL.class); VerifiableCredentialWithClaims passportVc = passport.issue( key.getId(), new PassportNL("John Smith") ); VcDecorator claimsModelExample = client.vcDecorator(ClaimsModelExample.class); VerifiableCredentialWithClaims claimsModelExampleVc = claimsModelExample.issue( key.getId(), new ClaimsModelExample(passportVc.toLinkedCredentialUnknown()) ); LinkedCredentialUnknown passportLinkedCredential = claimsModelExampleVc.getClaims().passport; UnknownVerifiableCredential passportUnknownVc = passportLinkedCredential.dereferenceVerifiableCredential(); if (passportUnknownVc.canMap(PassportNL.class)) { VerifiableCredentialWithClaims linkedPassportVc = passportUnknownVc.map(PassportNL.class); linkedPassportVc.getClaims().nameNL; // "John Smith" } else { VerifiableCredentialWithClaims linkedPassportVc = passportUnknownVc.map(PassportDE.class); linkedPassportVc.getClaims().nameDE; } ``` #### Further reading[​](#further-reading "Direct link to Further reading") * [Link files to credentials](/ssi/sdk/linked-data/link-files.md) * [Issue credentials](/ssi/sdk/credential-lifecycle/issue-credential.md) --- ### Link files to credentials In many cases, verifiable credentials need to include additional supporting documents, such as PDFs, images, or other file types. The Truvity SDK allows you to securely link external files to your credentials, enriching the data and providing further evidence to support the claims in the credential. Prerequisites * [Install and configure the SDK](/ssi/sdk/getting-started/installation.md) * [Define credential schema](/ssi/sdk/credential-lifecycle/define-credential-schema.md) * [Create a draft](/ssi/sdk/credential-lifecycle/create-draft.md) #### Why link files?[​](#why-link-files "Direct link to Why link files?") Linking files to credentials is particularly useful for: * **Digitizing Existing Documents (Creating Digital Twins)**: Transform physical documents into verifiable credentials by attaching their digital versions (for example, scans or electronic copies) to a credential. This process creates a “digital twin,” allowing the original document to be securely shared and verified. * **Supporting Documentation**: Attach evidence to a credential, such as a scanned certificate, diploma, or ID card. * **Rich Data Representations**: Provide additional context or resources that help verifiers understand the credential more deeply. * **Compliance**: Attach regulatory documents or contracts required by specific industries (for example, legal agreements or compliance certificates). #### Upload a file[​](#upload-a-file "Direct link to Upload a file") Before you link a file to a credential, you need to upload the file blob to the server. This section outlines the process for uploading a file to the Truvity API and creating a lightweight file representation (a file resource) using the `createLinkedFile()` method. ##### Read the file[​](#read-the-file "Direct link to Read the file") **Option 1: use a buffer** This method is straightforward, but not recommended for large files, as it can exhaust available memory. For example: * TypeScript * Java ```ts const fileBlob = Buffer.from('hello world', 'utf8') ``` ```java import java.nio.charset.StandardCharsets; byte[] fileBlob = "hello world".getBytes(StandardCharsets.UTF_8); ``` **Option 2: use a readable stream** This method creates a pointer to the file location without immediately loading the file into memory. This is ideal for large files, as data is read incrementally when needed. For example: * TypeScript * Java ```ts import fs from 'fs'; const fileBlob = fs.createReadStream('path/to/your/file.txt') ``` ```java import java.io.File; File fileBlob = new File("path/to/your/file.txt"); ``` ##### Upload the file and create a file resource[​](#upload-the-file-and-create-a-file-resource "Direct link to Upload the file and create a file resource") Use the `createLinkedFile()` method to upload the file to the API and create a file resource, which is a lightweight SDK representation. This intermediate representation: * Provides access to the original file resource. * Allows you to download the uploaded file. * Can be linked to a draft. - TypeScript - Java ```ts const uploadedFile = await client.createLinkedFile(fileBlob); ``` ```java import com.truvity.api.documents.models.LinkedFile; LinkedFile linkedFile = client.createLinkedFile(fileBlob); ``` note Under the hood, the `createLinkedFile()` method utilizes a combination of [`fileUpload`](/ssi/api-reference.md#tag/files/operation/FileUpload) and [`fileCreate`](/ssi/api-reference.md#tag/files/operation/FileCreate) API calls. If you do not want to use the `createLinkedFile()` method, you need to do the following to create a file: 1. Reserve space for the file in S3 using `fileUpload()`. 2. Upload the file to the reserved location in S3 using the programming language's HTTP request feature. 3. Finalize the upload and creates the API resource using `fileCreate()`. #### Create user-defined types (UDTs) definition for linked files[​](#create-user-defined-types-udts-definition-for-linked-files "Direct link to Create user-defined types (UDTs) definition for linked files") To link a file to a credential, you first need to create a [user-defined types (UDTs)](/ssi/sdk/credential-lifecycle/user-defined-types.md) definition for the credential. Use the decorator and the `LinkedFile` custom claim type: * TypeScript * Java ```ts @VcSchema() class ClaimsModelExample { @VcNotEmptyClaim fileAttachment!: LinkedFile; } ``` ```java @VcSchema class ClaimsModelExample { @NotEmpty private LinkedFile fileAttachment; ClaimsModelExample(LinkedFile file) { this.fileAttachment = file; } } ``` #### Link the file to a credential[​](#link-the-file-to-a-credential "Direct link to Link the file to a credential") After defining the UDT, create a draft that includes the uploaded file as a claim: * TypeScript * Java ```ts const claimsModelExample = await client.createVcDecorator(ClaimsModelExample); const claimsModelExampleDraft = await claimsModelExample.create({ claims: { fileAttachment: uploadedFile, }, }); ``` ```java import com.truvity.api.documents.credential.VcDecorator; import com.truvity.api.types.ResourceDraft; VcDecorator claimsModelExample = client.vcDecorator(ClaimsModelExample.class); ResourceDraft claimsModelExampleDraft = claimsModelExample.create(new ClaimsModelExample(uploadedFile)); ``` #### File immutability and deduplication logic[​](#file-immutability-and-deduplication-logic "Direct link to File immutability and deduplication logic") Before a file is stored, the API ensures immutability and deduplication by following these steps: 1. **Calculate the file hash** - A `multihash` is computed based on the file content to create a unique fingerprint. 2. **Validate file `id` (if provided)** - If a previously created file `id` is included in the request body, the system: * Checks whether another file already exists with the same `id`. * If a different file is found with the same `id`, a 409 `ConflictResource` error is returned. 3. **Generate file `id` (if missing)** - If no file `id` is provided, the system generates one automatically. note This is required for DIDComm-based file exchanges. 4. **Deduplication Check** - The system prevents creating resource duplicates by searching for matching files based on file hash, metadata (filename and media type), and file `id` when provided. 5. **Return existing file (if duplicate)** - If an identical file already exists, the system returns it instead of creating a new resource. 6. **Store the new file (if unique)** - If no duplicate is found, the file is stored as a new resource. #### Further reading[​](#further-reading "Direct link to Further reading") * [Link credentials to each other](/ssi/sdk/linked-data/link-credentials.md) * [Issue credentials](/ssi/sdk/credential-lifecycle/issue-credential.md) --- ### Model data with labels and annotations Labels and annotations provide a powerful way to organize and model [REST resources](/ssi/overview/reference/rest-resources-operations.md) in the Truvity platform, allowing you to quickly categorize, filter, and retrieve resources based on specific attributes with [faceted search](/ssi/sdk/manage-data/use-faceted-search.md). #### Add labels and annotations to a draft[​](#add-labels-and-annotations-to-a-draft "Direct link to Add labels and annotations to a draft") Prerequisites * [Install and configure the SDK](/ssi/sdk/getting-started/installation.md) * [Define credential schema](/ssi/sdk/credential-lifecycle/define-credential-schema.md) * [Create a draft](/ssi/sdk/credential-lifecycle/create-draft.md) To add labels or annotations to a draft resource, call the [`update`](/ssi/api-reference.md#tag/drafts/operation/DraftUpdate) method: * TypeScript * Java ```ts const updatedDraft = await createdDraft.update({ labels: { property1: "string", }, annotations: { property2: "string", } }); ``` ```java var updatedDraft = createdDraft.update(null, Map.of("property1", "string"), Map.of("property2", "string")); ``` #### Add labels and annotations to an issued credential[​](#add-labels-and-annotations-to-an-issued-credential "Direct link to Add labels and annotations to an issued credential") Prerequisites * [Install and configure the SDK](/ssi/sdk/getting-started/installation.md) * [Define credential schema](/ssi/sdk/credential-lifecycle/define-credential-schema.md) * [Create a draft](/ssi/sdk/credential-lifecycle/create-draft.md) * [Issue credential](/ssi/sdk/credential-lifecycle/issue-credential.md) You can add labels and annotations to an issued credential resource by either calling the `update` method on the `VerifiableCredential` instance or by using the [`CredentialUpdateLabels`](/ssi/api-reference.md#tag/credentials/operation/CredentialUpdateLabels) and [`CredentialUpdateAnnotations`](/ssi/api-reference.md#tag/credentials/operation/CredentialUpdateAnnotations) API endpoints directly. * TypeScript * Java ```ts const updatedCredential = await credential.update({ labels: { property1: "string", }, annotations: { property2: "string", }, }); ``` ```java var updatedCredential = credential.update(new UpdatePayload(Map.of("property1", "string"), Map.of("property2", "string"))); ``` #### Add labels and annotations to a verifiable presentation[​](#add-labels-and-annotations-to-a-verifiable-presentation "Direct link to Add labels and annotations to a verifiable presentation") Prerequisites * [Install and configure the SDK](/ssi/sdk/getting-started/installation.md) * [Define credential schema](/ssi/sdk/credential-lifecycle/define-credential-schema.md) * [Create a draft](/ssi/sdk/credential-lifecycle/create-draft.md) * [Issue credential](/ssi/sdk/credential-lifecycle/issue-credential.md) * [Issue presentation](/ssi/sdk/credential-lifecycle/share-credential-and-presentation.md) To add labels to the issued verifiable presentation resource, call the [`presentationUpdateLabels`](/ssi/api-reference.md#tag/presentations/operation/PresentationUpdateLabels) method: * TypeScript * Java ```ts const updatedPresentation = await presentation.presentationUpdateLabels({ labels: { property1: "string", }, }); ``` ```java var updatedPresentation = presentation.presentationUpdateLabels(null, Map.of("property1", "string")); ``` To add annotations to the issued verifiable presentation resource, call the [`presentationUpdateAnnotations`](/ssi/api-reference.md#tag/presentations/operation/PresentationUpdateAnnotations) method: * TypeScript * Java ```ts const updatedPresentation = await presentation.presentationUpdateAnnotations({ annotations: { property1: "string", }, }); ``` ```java var updatedPresentation = presentation.presentationUpdateAnnotations(null, Map.of("property1", "string")); ``` #### Add labels and annotations to a DIDComm message[​](#add-labels-and-annotations-to-a-didcomm-message "Direct link to Add labels and annotations to a DIDComm message") Prerequisites * [Install and configure the SDK](/ssi/sdk/getting-started/installation.md) * [Define credential schema](/ssi/sdk/credential-lifecycle/define-credential-schema.md) * [Create a draft](/ssi/sdk/credential-lifecycle/create-draft.md) * [Issue credential](/ssi/sdk/credential-lifecycle/issue-credential.md) * [Share credential and presentation](/ssi/sdk/credential-lifecycle/share-credential-and-presentation.md) To add labels to a DIDComm message, call the [`DidcommMessageUpdateLabels`](/ssi/api-reference.md#tag/didcomm-messages/operation/DidcommMessageUpdateLabels) method: * TypeScript * Java ```ts const updatedDidcommMessage = await client.didcommMessages.didcommMessageUpdateAnnotations(didcommMessageId, { labels: { property1: "string", }, }); ``` ```java var updatedDidcommMessage = client.didcommMessages() .didcommMessageUpdateLabels( didcommMessageId, DidcommMessageUpdateLabelsInput.builder().labels("property1", "string").build()); ``` To add annotations to a DIDComm message, call the [`DidcommMessageUpdateAnnotations`](/ssi/api-reference.md#tag/didcomm-messages/operation/DidcommMessageUpdateAnnotations) method: * TypeScript * Java ```ts const updatedDidcommMessage = await client.didcommMessages.didcommMessageUpdateAnnotations(didcommMessageId, { annotations: { property1: "string", }, }); ``` ```java var updatedDidcommMessage = client.didcommMessages() .didcommMessageUpdateAnnotations( didcommMessageId, DidcommMessageUpdateAnnotationsInput.builder() .annotations("property1", "string") .build()); ``` --- ### Use faceted search Faceted search is a powerful tool that allows you to filter and retrieve [REST resources](/ssi/overview/reference/rest-resources-operations.md) based on multiple criteria or attributes, such as labels, annotations, status, and dates. This is especially useful when managing large sets of resources that need to be filtered efficiently. Prerequisites * [Install and configure the SDK](/ssi/sdk/getting-started/installation.md) * [Define credential schema](/ssi/sdk/credential-lifecycle/define-credential-schema.md) * [Create a draft](/ssi/sdk/credential-lifecycle/create-draft.md) #### Example: Basic faceted search[​](#example-basic-faceted-search "Direct link to Example: Basic faceted search") Here is an example of a simple faceted search using labels: * TypeScript * Java ```ts const result = await client.credentials.credentialSearch({ filter: [ { labels: { operator: 'EQUAL', value: 'employment', } }, }, ], }); ``` ```java var searchResult = client.credentials() .credentialSearch(CredentialSearchRequest.builder() .filter(List.of(CredentialFilter.builder() .labels(List.of(CredentialFilterLabelsItem.equal( KeyEqualLabelKeyLabelValue.builder() .key("value") .value("employment") .build() ))).build() )).build() ); ``` #### Example: Advanced faceted search with multiple criteria[​](#example-advanced-faceted-search-with-multiple-criteria "Direct link to Example: Advanced faceted search with multiple criteria") The example below covers the case of finding credentials of a specific credential type (`documentType`) that has a specific linked verifiable credential (`previouslyIssuedVC`): * TypeScript * Java ```ts const result = await client.credentials.credentialSearch({ filter: [ { data: { type: { operator: 'IN', values: [documentType.getCredentialTerm()], }, linkedCredentials: { operator: 'IN', values: [previouslyIssuedVC.toLinkedCredential().id], }, }, }, ], }); ``` ```java var advancedSearchResult = client.credentials() .credentialSearch(CredentialSearchRequest.builder() .filter(List.of(CredentialFilter.builder() .data(CredentialFilterData.builder() .type(CredentialFilterDataType.in(new NestedInPrimitiveString( List.of(documentType.getCredentialTerm()) ))) .linkedCredentials(CredentialFilterDataLinkedCredentials.in(new NestedInPrimitiveString( List.of(previouslyIssuedVC.descriptor().id()) ))) .build()) .build())) .build()); ``` #### Further reading[​](#further-reading "Direct link to Further reading") * [Assign labels to resources](/ssi/sdk/manage-data/model-with-labels.md) --- ### View credential history #### Why track credential history?[​](#why-track-credential-history "Direct link to Why track credential history?") Tracking the history of a credential is important for: * **Auditing**: Monitor who created, updated, or issued a credential, and track any changes made. * **Compliance**: Ensure compliance with regulatory requirements by maintaining a complete record of a credential's lifecycle. * **Data Integrity**: Validate that a credential has not been tampered with or altered without authorization. Prerequisites * [Install and configure the SDK](/ssi/sdk/getting-started/installation.md) * [Define credential schema](/ssi/sdk/credential-lifecycle/define-credential-schema.md) * [Create a draft](/ssi/sdk/credential-lifecycle/create-draft.md) * [Issue credential](/ssi/sdk/credential-lifecycle/issue-credential.md) #### Example: View credential history[​](#example-view-credential-history "Direct link to Example: View credential history") To view the history of a credential, use the [`credentialHistory`](/ssi/api-reference.md#tag/credentials/operation/CredentialHistory) method: * TypeScript * Java ```ts await client.credentials.credentialHistory("id", { ifNoneMatch: "5db68c06-1a68-11e9-8341-68f728c1ba70" }); ``` ```java client.credentials() .credentialHistory("id", CredentialHistoryRequest.builder() .ifNoneMatch("5db68c06-1a68-11e9-8341-68f728c1ba70").build()); ``` Where `ifNoneMatch` declares a list of identifiers required to fail matching all the current resource version identifiers as a pre-condition for executing the request on the server side. This is especially used in conjunction with an \* (asterisk) that matches all possible resource identifiers to ensure the initial creation of a resource. --- ### Error codes This page lists specific error codes you might encounter when defining or working with the Truvity SDK, along with guidance on how to resolve them. #### T001 - Missing `VcSchema` annotation on UDT definition[​](#T001 "Direct link to T001") When you define a user-defined type (UDT), you must add a `VcSchema` annotation to the type. Without this annotation, the Truvity SDK can't recognize the type as a UDT. The following examples show how to add the annotation in different languages. * TypeScript * Java ```ts @VcSchema() class SimpleCredential { @VcClaim name!: string; @VcClaim age!: number; } ``` ```java @VcSchema() public static class SimpleCredential { private Optional name; private Optional age; } ``` **Further reading:** [SDK quick start guide](/ssi/sdk/getting-started/quick-start.md) #### T002 - Unexpected type in serialization or deserialization[​](#T002 "Direct link to T002 - Unexpected type in serialization or deserialization") This error occurs when the type of a value during serialization or deserialization doesn’t match the UDT definition. When you serialize data, the error happens if a value doesn’t match the declared type in the UDT claim. To fix it, either update the source values to match the UDT definition or update the UDT definition to match the source values. When you deserialize data, the error happens if you change a UDT definition in a backward-incompatible way and try to deserialize existing data. For example, if you originally define a claim as an `integer` and later change it to a `string`, deserialization fails for existing data. To fix this, either revert the backward-incompatible change or update the UDT definition to stay compatible with the stored data. **Further reading:** [Define credential schema using UDT](/ssi/sdk/credential-lifecycle/define-credential-schema.md) #### T003 - Unsupported data type in a user-defined type (UDT)[​](#T003 "Direct link to T003 - Unsupported data type in a user-defined type (UDT)") This error occurs when a field in your user-defined type (UDT) uses a data type that the SDK does not accept. **Further reading:** [Supported data types](/ssi/sdk/reference/supported-data-types-for-udt-fields.md) #### T004 - Incompatible resource credential type[​](#T004 "Direct link to T004 - Incompatible resource credential type") This error occurs when you attempt to retrieve or operate with a credential using a `VcDecorator` bound to a different UDT. Each UDT requires its own `VcDecorator` so that the SDK applies the correct schema. The examples below show how to create and use a `VcDecorator` for two UDTs: `PersonalDetails` and `Address`. * TypeScript * Java ```ts @VcSchema() class PersonalDetails { @VcClaim name!: string; @VcClaim age!: number; } @VcSchema() class Address { @VcClaim street!: string; city!: string; } // This VcDecorator instance should be used for working with the // PersonalDetails UDT const peronalDetailsDecorator = client.createVcDecorator(PersonalDetails); const personalDetailsDraft = await personalDetailsDecorator.create({ claims: { name: "Alice", age: 30 } }); // This VcDecorator instance should be used for working with the // Address UDT const addressDecorator = client.createVcDecorator(Address); const addressDraft = await addressDecorator.create({ claims: { street: "Kinkerstraat", city: "Amsterdam" } }); ``` ```java @VcSchema class PersonalDetails { String name; int age; } @VcSchema class Address { String street; String city; } // This VcDecorator instance should be used for working with the // PersonalDetails UDT VcDecorator personalDetailsDecorator = client.vcDecorator(PersonalDetails.class); PersonalDetails personalDetailsData = new PersonalDetails(); personalDetailsData.name = "Alice"; personalDetailsData.age = 30; var draft = personalDetailsDecorator.create(personalDetailsData); // This VcDecorator instance should be used for working with the // Address UDT VcDecorator
addressDecorator = client.vcDecorator(Address.class); Address addressData = new Address(); addressData.street = "Kinkerstraat"; addressData.city = "Amsterdam"; var draft = addressDecorator.create(addressData); ``` #### T005 - Missing `slug` argument in `VcSchema` annotation on UDT definition[​](#T005 "Direct link to T005") The `slug` argument for the `VcSchema` annotation is mandatory when working with published stable schemas. Please remember that the `owner` argument currently works only with published schemas and requires the `slug` argument to be provided. The following examples show how to provide the `slug` argument to the annotation in different languages. * TypeScript * Java ```ts @VcSchema({ slug: 'SimpleCredential' }) class SimpleCredential { @VcClaim name!: string; @VcClaim age!: number; } ``` ```java @VcSchema(slug = "SimpleCredential") public static class SimpleCredential { private Optional name; private Optional age; } ``` **Further reading:** [Create a schema](/ssi/schemas/manage-schemas/create-schema.md), [Publish a schema](/ssi/schemas/manage-schemas/publish-schema.md) #### T006 - Schema owner differs from configured tenant[​](#T006 "Direct link to T006 - Schema owner differs from configured tenant") This error occurs when you try to publish a schema whose `owner` in the `VcSchema` annotation doesn't match the tenant ID configured in your SDK client. The SDK prevents publishing a schema to a tenant different from the one you're authenticated with. To fix this, make sure the `owner` argument in the `VcSchema` annotation matches the tenant ID of the client you're using, or remove the `owner` argument if you intend to publish the schema under the current tenant. * TypeScript * Java ```ts @VcSchema({ slug: 'SimpleCredential', owner: 'your-tenant-id' }) class SimpleCredential { @VcClaim name!: string; @VcClaim age!: number; } ``` ```java @VcSchema(slug = "SimpleCredential", owner = "your-tenant-id") public static class SimpleCredential { private Optional name; private Optional age; } ``` **Further reading:** [Create a schema](/ssi/schemas/manage-schemas/create-schema.md), [Publish a schema](/ssi/schemas/manage-schemas/publish-schema.md) --- ### Supported data types for user-defined type (UDT) fields The following data types are supported as field types within user-defined types (UDTs) when modeling credential schemas. Field types include primitives, complex types, and collections. You can also nest other UDTs as fields. * TypeScript * Java - `Boolean` - `Date` - `Number` - `String` - `Rfc3339Date` (ISO 8601 date string) - `Rfc3339DateTime` (ISO 8601 datetime string) - `LinkedCredential` (reference to another credential) - `LinkedFile` (reference to an attached file) - `Array` of any supported type - Another UDT (nested) * Primitives: `boolean`, `int`, `long`, `float`, `double` * Boxed types: `Boolean`, `Integer`, `Long`, `Float`, `Double` * Date/time types: `LocalDate`, `OffsetDateTime` * Identifiers: `UUID` * Strings: `String` * Credential references: `LinkedCredential`, `ResourceCredential` * File references: `LinkedFile`, `ResourceFile` * Lists: `List` where `T` is one of the supported types * Another UDT (nested) --- ## Support ### Support If you need help with the Truvity Platform, we are here to assist you. Currently, all product and technical support is provided through our Discord community. #### Get support on Discord[​](#get-support-on-discord "Direct link to Get support on Discord") Join our Discord server to connect with the Truvity team and other developers. You can ask questions, share your experiences, and get assistance with any product or technical issues you may encounter. Join the Truvity [Discord server](https://discord.gg/pN8AEcBFV9). ##### How to ask for support[​](#how-to-ask-for-support "Direct link to How to ask for support") 1. **Join**: Click the link to join our Discord server. 2. **Introduce Yourself**: Head to the `#general` channel and say hello! 3. **Ask Your Question**: Navigate to the `#support` channel and ask your question. Provide as much detail as possible, including the context of the question or issue and any error messages you encounter. Our team and community members are there to help you troubleshoot and resolve any issues. ##### Why use Discord for support?[​](#why-use-discord-for-support "Direct link to Why use Discord for support?") Using Discord allows us to provide real-time support and create an active community where developers can collaborate, share insights, and learn from each other. It is a space where you can find answers quickly and connect with others working on similar projects. --- ## Vocab ### Truvity Verifiable Credentials Vocabulary This document defines the Truvity Verifiable Credentials Vocabulary - an [RDF Schema](https://www.w3.org/TR/rdf-schema/) (RDFS) vocabulary used by verifiable credentials (VC) issued under the [Verifiable Credentials Data Model](https://www.w3.org/TR/vc-data-model-2.0) (VCDM). The document contains a list of terms (properties and classes from the VCDM) that extend semantics of credential data using [capabilities provided by the Truvity platform](https://docs.truvity.com/overview/about-platform/capabilities). The primary purpose of this document is to explain the semantics of values defined by these terms and guide developers on using them to ensure interoperability. #### LinkedCredential[​](#linkedcredential "Direct link to LinkedCredential") ##### Description[​](#description "Direct link to Description") A Linked Credential is a way for a credential to refer to another VC. Creating relationships between different credentials is often useful. For example, you might link a diploma credential to a professional license, or a national ID to a work visa. The Truvity SDK allows you to link credentials together to form a hierarchy of related data. A value of type `LinkedCredential`, therefore, represents a reference to a previously issued VC. Having such a value as a claim on another VC establishes a link from that VC to the first one. ##### Semantics[​](#semantics "Direct link to Semantics") A link to a VC issued according to VCDM, including an integrity check. Values with this term in their type MUST contain two properties: `id` and `digestMultibase`. The `id` MUST be a URI of the linked VC. The `digestMultibase` must contain the SHA-256 hash of the linked VC encoded in [multibase](https://github.com/multiformats/multibase) format. The hash must be calculated using the canonized form of the VC as specified by the [RDF Dataset Canonicalization Algorithm](https://www.w3.org/TR/rdf-canon/) (RDFC). If the calculated hash of the dereferenced VC does not match the value in `digestMultibase`, the value MUST be considered invalid. ##### Example[​](#example "Direct link to Example") The following is an example of a value of type `LinkedCredential`: ```json { "type": "LinkedCredential", // resolved IRI: https://docs.truvity.com/vocab#LinkedCredential "id": "https://ssi.truvity.com/tenants/1d3646a2-650a-41ff-81df-4744343533b6/credentials/0d35167d-8e1a-4806-8595-8fc3c3ec2191", "digestMultibase": "uEiC1REFpQHY89iXN2DXCvcvVaCkFlBGgBtTJhupjv_Kvmw" } ``` In the example below using the Truvity SDK, the `ProfessionalLicense` VC refers to the `Diploma` VC. This has two consequences: * In order to issue a `ProfessionalLicense` VC, one must provide a `Diploma` VC. * Having a `ProfessionalLicense` VC, one is able to retrieve the linked `Diploma` VC. - TypeScript - Java ```ts @VcSchema() class Diploma { @VcNotEmptyClaim institution!: string; } @VcSchema() class ProfessionalCertificate { @VcNotEmptyClaim name!: string; @VcNotEmptyClaim diploma!: LinkedCredential; } ``` ```java @VcSchema() class Diploma { @NotEmpty private String institution; } @VcSchema() class ProfessionalCertificate { @NotEmpty private String name; @NotEmpty private LinkedCredential diploma; } ``` ##### Further reading[​](#further-reading "Direct link to Further reading") *[SDK documentation on LinkedCredentials](/ssi/sdk/linked-data/link-credentials.md)* *** #### LinkedFile[​](#linkedfile "Direct link to LinkedFile") ##### Description[​](#description-1 "Direct link to Description") In many cases, VCs need to include additional supporting documents, such as PDFs, images, or other file types. The Truvity SDK allows you to securely link external files to your credentials, enriching the data and providing further evidence to support the claims in the credential. A value of type `LinkedFile`, therefore, represents a reference to that file. Having such a value as a claim on a VC establishes a link from that VC to the file. The Truvity SDK provides methods to upload, retrieve, and handle these files in a lightweight manner. ##### Semantics[​](#semantics-1 "Direct link to Semantics") A link to a file with an integrity check. Values with this term in their type MUST contain two properties: `id` and `digestMultibase`. The `id` MUST be a URI of the linked file. The `digestMultibase` must contain the SHA-256 hash of the linked file blob encoded in [multibase](https://github.com/multiformats/multibase) format. If the calculated hash of the dereferenced file blob does not match the value in `digestMultibase`, the value MUST be considered invalid. ##### Example[​](#example-1 "Direct link to Example") The following is an example of a value of type `LinkedFile`: ```json { "type": "LinkedFile", // resolved IRI: https://docs.truvity.com/vocab#LinkedFile "id": "https://ssi.truvity.com/tenants/b17de333-4485-4716-986c-6ea549989e06/files/ccb8ba0d-5ed7-4f8d-b8d9-1f1e67bed461", "digestMultibase": "uEiBE7LZKwrOIPYLL1cFqNhxSsReYRQunMEY1H0dARG_2Sw" } ``` In the example below using the Truvity SDK, the `ProfessionalCertificate` VC has a diploma claim as a `LinkedFile`. This has two consequences: * In order to issue a `ProfessionalCertificate` VC, one must provide a diploma file. * Having a `ProfessionalLicense` VC, one is able to retrieve the linked diploma file. - TypeScript - Java ```ts @VcSchema() class ProfessionalCertificate { @VcNotEmptyClaim name!: string; @VcNotEmptyClaim diploma!: LinkedFile; } ``` ```java @VcSchema class ProfessionalCertificate { @NotEmpty String name; @NotEmpty LinkedFile diploma; } ``` ##### Further reading[​](#further-reading-1 "Direct link to Further reading") *[SDK documentation on LinkedFiles](/ssi/sdk/linked-data/link-files.md)* ---