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 credentialStatus for 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.

CURL

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 is test.enterprise-sandbox.waltid.dev on 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 issuer2 for 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, or doctype). 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 via credentialStatus.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 in credentialConfigurations (only valid for dc+sd-jwt configurations). If omitted, the issuer serves a minimal auto-generated document. This is distinct from a configuration's credential_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-attestation method is included, token requests must carry valid OAuth-Client-Attestation and OAuth-Client-Attestation-PoP headers. 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 missing vct).
  • 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:

CURL

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 named test, your default Base URL will be test.enterprise-sandbox.walt.dev when 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:

  1. Issue your first credential – End-to-end guide from profile to a credential in a wallet.
  2. Create credential profiles – Define reusable configurations for each credential type.
  3. Configure display metadata – Customize how your issuer appears in wallets.
Last updated on August 5, 2026