Skip to main content

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
  • Access to a Truvity EUDIW Connector instance. The connector is not publicly available—contact Truvity at hello@truvity.com to get access.
  • A running connector instance with its public base URL configured and a callback URL pointing to your backend endpoint (for example, http://localhost:3000/callback/issuance). See connector architecture for the deployment model and how callbacks are delivered.
  • An X.509 access certificate configured in the connector. See Manage certificates to generate test certificates or import production ones.
  • A callback endpoint reachable from the connector over internal networking. The connector delivers issuance results to this endpoint.
  • An Issuer Signing Certificate configured in the connector for signing credentials.
  • Type Metadata configured for the credential type you want to issue.
  • Access to the internal management API on port 8081.

The connector implements OID4VCI using the pre-authorized code flow under the High Assurance Interoperability Profile (HAIP). You don't need to configure protocol options—the connector applies HAIP-compliant settings by default.

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.

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 -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):

{
"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 for details.

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.

# 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"
}'
# 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.

Next steps

Further reading