Developers

LutraID issues credentials to EUDI-compatible wallets over OpenID4VCI 1.0 and verifies presentations over OpenID4VP 1.0, including the HAIP profile. You provision issuers, verifiers and profiles in the dashboard, then drive them from your backend with a scoped API key.

What you can build

Two credential formats: dc+sd-jwt (SD-JWT VC) and mso_mdoc (ISO mdoc/mDL). Presentation requests use DCQL exclusively.

Not supported today: W3C Verifiable Credentials in any representation, DID-based identifiers, presentation_exchange/presentation_definition requests, or mTLS sender-constrained tokens.

How an integration is shaped

StepRuns where
Create an issuer or verifier, assign profilesDashboard
Mint an API key scoped to itDashboard
Create an offer or a verification requestYour backend
Render the returned URI as a QR code or linkYour frontend
Receive a webhook or poll for the outcomeYour backend

Wallets talk to LutraID directly over the protocol endpoints. You never proxy them. Creating organizations, issuers, verifiers, document types and issuance/verification profiles is a dashboard task, not an API call — see the Guides. Your calls reference a profile by ID; you don't define credential schemas or DCQL queries through this API.

Base URL

Paths in these pages are relative to your deployment's API base URL. The generated OpenAPI reference is served by the API itself at /doc/reference, the raw document at /doc. If anything in these pages and the live /doc output disagree, /doc wins — it's generated directly from the running server.

Environment

export LUTRAID_API="https://your-lutraid-host"
export LUTRAID_KEY="iss_..."
export ORG="<organizationId>" ISSUER="<issuerId>" VERIFIER="<verifierId>"

Every example below assumes these are already in scope.

Java with Spring Boot

The Java (Spring Boot) tabs use the synchronous RestClient in Spring Boot 3.2 or later, with Java 17 or later. In a Boot 3 application, include spring-boot-starter-web; in Boot 4, include spring-boot-starter-restclient. Let your Spring Boot dependency management select the versions. See Spring's client guidance.

Save the service below as LutraIdService.java in a package scanned by your application. Add a request method and its response record from an API page inside the class; methods and records repeated across pages should be declared only once. Inject LutraIdService into your application's components and call its methods with your organization, issuer or verifier, and profile IDs.

LutraIdService.java

import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestClient;

@Service
public class LutraIdService {
    private final RestClient client;
    private final String apiKey;

    public LutraIdService(
            RestClient.Builder builder,
            @Value("${LUTRAID_API}") String apiBaseUrl,
            @Value("${LUTRAID_KEY}") String apiKey) {
        this.client = builder.baseUrl(apiBaseUrl).build();
        this.apiKey = apiKey;
    }

    // Paste a request method and its response record here.
}

Set LUTRAID_API and LUTRAID_KEY in your application's environment. The constructor uses Boot's configured RestClient.Builder so its JSON converters and HTTP configuration are retained. This service represents one scoped key. Use separate service classes or instances for issuer and verifier keys when an application needs both; do not combine issuance and verification methods under the same key. A key is also tied to the organization and issuer or verifier IDs you pass to the methods.

Request bodies are Java maps and lists, which Spring serializes as JSON with proper escaping. Responses are Java records containing the fields each example uses; Boot's default JSON configuration ignores additional response fields. If you customize the JSON converters, preserve that behavior. .retrieve() throws RestClientResponseException for HTTP 4xx/5xx responses; callers can inspect getStatusCode() and getResponseBodyAsString() to handle API errors. Network failures and timeouts throw ResourceAccessException; retry decisions should follow the endpoint's semantics, including reusing the idempotency key for authorization-code offers.

For an application without Spring, see Java without Spring.

Conventions

  • Authentication is the X-API-Key header. See Authentication.
  • Every response carries X-Request-ID; an inbound W3C traceparent is honoured and threaded through logs and diagnostics.
  • Learn outcomes from webhooks or by polling.

Was this page helpful?