Setup
This guide walks you through creating an Issuer2 service inside a tenant. The service declares which credential types it can issue (credentialConfigurations) and which KMS signs its tokens. If you don't have a tenant yet, learn how to create one here.
Prerequisites
Before creating an Issuer2 service, ensure you have:
- A tenant — An existing tenant in your organization.
- A KMS service — A Key Management Service for storing signing keys.
- A token key — A key in the KMS used to sign OID4VCI access tokens.
- A Credential Status Service (optional) — Only needed if a credential profile will use
credentialStatusfor revocation/suspension. See Credential Status Service.
Create an Issuer2 Service
Services are created through the generic resource API. The body's type field selects the service kind (issuer2), and the new service's own ID is taken from the target in the path.
Endpoint: POST /v1/{target}/resource-api/services/create | API Reference
Example Request
curl -X 'POST' \
'https://{orgID}.enterprise-sandbox.waltid.dev/v1/{target}/resource-api/services/create' \
-H 'accept: application/json' \
-H 'Authorization: Bearer {yourToken}' \
-H 'Content-Type: application/json' \
-d '{
"type": "issuer2",
"baseUrl": "https://myorg.enterprise-sandbox.waltid.dev",
"kms": "waltid.tenant1.kms1",
"tokenKeyId": "waltid.tenant1.kms1.tokenKey",
"credentialConfigurations": {
"identity_credential_vc+sd-jwt": {
"format": "dc+sd-jwt",
"vct": "{vctBaseURL}/identity_credential",
"cryptographic_binding_methods_supported": ["jwk", "did:key", "did:web"],
"credential_signing_alg_values_supported": ["ES256"],
"proof_types_supported": {
"jwt": { "proof_signing_alg_values_supported": ["ES256"] }
}
},
"UniversityDegree_jwt_vc_json": {
"format": "jwt_vc_json",
"cryptographic_binding_methods_supported": ["jwk", "did:key", "did:web", "did:jwk"],
"credential_signing_alg_values_supported": ["ES256", "EdDSA"],
"proof_types_supported": {
"jwt": { "proof_signing_alg_values_supported": ["ES256", "EdDSA"] }
},
"credential_definition": {
"type": ["VerifiableCredential", "UniversityDegree"]
}
},
"org.iso.18013.5.1.mDL": {
"format": "mso_mdoc",
"doctype": "org.iso.18013.5.1.mDL",
"cryptographic_binding_methods_supported": ["cose_key"],
"credential_signing_alg_values_supported": [-7, -9],
"proof_types_supported": {
"jwt": { "proof_signing_alg_values_supported": ["ES256"] }
}
}
},
"issuerDisplayConfiguration": [
{
"name": "My Organization Issuer",
"locale": "en-US",
"logo": {
"uri": "https://example.com/logo.png",
"alt_text": "Organization logo"
}
}
]
}'
Path Parameters
- orgID: String (required) - Your organization ID, i.e. its base URL. For an organization named
test, this istest.enterprise-sandbox.waltid.devon the sandbox environment. - target: String (required) - The resource identifier for the new issuer service,
{organizationID}.{tenantID}.{newIssuerServiceID}, e.g.waltid.tenant1.issuer1.
Header Parameters
- Authorization: String (required) - Bearer token for Enterprise Stack authentication. Format:
Bearer {token}.
Body Parameters
- type: String (required) - Must be
issuer2for the Issuer2 Service. - kms: resourceIdentifier (required) - Reference to a KMS service in the same tenant, e.g.
waltid.tenant1.kms1. - tokenKeyId: resourceIdentifier (required) - Reference to a key in the KMS used to sign OID4VCI access tokens, e.g.
waltid.tenant1.kms1.tokenKey. - credentialConfigurations: Object (required) - Map of the credential types this issuer supports, keyed by credential configuration ID. Each value declares
format, signing/binding support, and format-specific fields (vct,credential_definition, ordoctype). The example uses the self-hosted{vctBaseURL}VCT placeholder and integer COSE signing algorithms for the mDoc. See Credential Types for the full field reference, validation rules, and per-format options. - dependencies: Array of Strings (optional) - Resource paths of other services this issuer depends on, e.g.
["waltid.tenant1.credstatus1"]. Each listed service must already exist. Required when any credential profile will reference a Credential Status Service viacredentialStatus.statusCredentialConfig(see Credential Status) — otherwise credential issuance fails. Can also be set (or added to) after creation — see Attaching Dependencies Later below. - baseUrl: String (optional) - The public URL where the issuer is reachable; included in credential offers and OpenID metadata, e.g.
https://{orgID}.yourEnterpriseStackUrl.com. - issuerDisplayConfiguration: Array (optional) - Display metadata for the issuer, one entry per locale (
name,locale,logo). See Display Configuration. - sdJwtVcTypeMetadataConfiguration: Object (optional) - Not shown above. Supplies a custom SD-JWT VC Type Metadata document to serve for a self-hosted
{vctBaseURL}VCT, keyed by the same credential configuration ID as incredentialConfigurations(only valid fordc+sd-jwtconfigurations). If omitted, the issuer serves a minimal auto-generated document. This is distinct from a configuration'scredential_metadata(wallet display/claims). See VCT Handling. - clientAuthenticationConfig: Object (optional) - Declares which client authentication methods the issuer supports (anonymous pre-authorized code access and/or attestation-based wallet authentication). When a
client-attestationmethod is included, token requests must carry validOAuth-Client-AttestationandOAuth-Client-Attestation-PoPheaders. See Client Attestation — Issuer Integration for JSON shape, examples, and how this maps to authorization server metadata. - credentialEncryptionKey: resourceIdentifier – Reference to an EC P-256 key in KMS used for OID4VCI Credential Request decryption and Credential Response encryption.
credentialEncryptionKey enables OID4VCI Credential Request encryption and Credential Response encryption.
Issuer2 supports this profile:
- Key type: EC P-256
- JWE
alg:ECDH-ES - JWE
enc:A128GCM - Compression: not supported
When configured, issuer metadata includes credential_request_encryption and credential_response_encryption with encryption_required = false.
Wallets can keep using normal JSON credential requests. Wallets that send an encrypted Credential Request as application/jwt and include credential_response_encryption receive the Credential Response as an encrypted JWE.
{
"credentialEncryptionKey": "waltid.tenant1.kms1.ecKey1"
}
Use a dedicated key for credential encryption. Do not reuse the token signing key or credential signing keys.
Omit clientAuthenticationConfig entirely, or set supportedMethods to an empty list, to keep the default behavior where this layer does not enforce client authentication. Use supportedMethods with only preauth-anonymous when you want OID4VCI pre-authorized token requests without client_id but no wallet attestation.
Example Response
{
"id": "waltid.tenant1.issuer1",
"type": "issuer2",
"baseUrl": "https://myorg.enterprise-sandbox.waltid.dev",
"kms": "waltid.tenant1.kms1",
"tokenKeyId": "waltid.tenant1.kms1.tokenKey",
"credentialConfigurations": { "...": "..." },
"issuerDisplayConfiguration": [ "..." ]
}
Response Fields
- id: String - The resource identifier of the created issuer service,
{organizationID}.{tenantID}.{issuerServiceID}. - type: String - The service type,
issuer2.
Response Codes
201— Service created successfully.400— Invalid request body (e.g. an SD-JWT VC configuration missingvct).401— Invalid or missing authentication token.409— A service with this ID already exists.
🎉 You've created an Issuer2 service.
Credential Types
The credentialConfigurations map above declares one entry per credential type. Its shape depends on the format (vct for SD-JWT VC, credential_definition for W3C JWT, doctype for mDoc), and the service validates format-specific rules on create — binding/proof co-dependency, DID method form, and JOSE-vs-COSE signing identifiers.
For the full field reference, validation rules, per-format examples, and VCT handling, see Credential Types Configuration.
Attaching Dependencies Later
dependencies doesn't have to be set at creation time. You can attach a service (e.g. a Credential Status Service) to an existing Issuer2 service:
Endpoint: /v2/{target}/issuer-service-api/dependencies/add | API Reference
Example Request
curl -X 'POST' \
'https://{orgID}.enterprise-sandbox.waltid.dev/v2/{target}/issuer-service-api/dependencies/add' \
-H 'accept: */*' \
-H 'Authorization: Bearer {yourToken}' \
-d 'waltid.tenant1.credstatus1'
Body
waltid.tenant1.credstatus1
Path Parameters
orgID: - When performing operations within an organization, it is essential to use the organization's Base URL or another valid host alias. For example, if your organization is namedtest, your default Base URL will betest.enterprise-sandbox.walt.devwhen using the sandbox environment.target: resourceIdentifier - The target indicates the organization + tenant + Issuer2 service to which to attach the dependency ({organizationID}.{tenantID}.{issuerServiceID}), e.g.waltid.tenant1.issuer1.
Body Parameters
- Specifies the resource path of the service that should be attached as a dependency.
Response Codes
201- Dependency attached.
Next Steps
After creating your Issuer2 service:
- Issue your first credential – End-to-end guide from profile to a credential in a wallet.
- Create credential profiles – Define reusable configurations for each credential type.
- Configure display metadata – Customize how your issuer appears in wallets.
