Create a Credential Profile
This guide walks you through creating a credential profile, which defines the default configuration for issuing a specific type of credential.
Prerequisites
Before creating a profile, ensure you have:
- An Issuer2 service — A running issuer service. See Setup.
- A KMS key — A key for signing credentials, in a KMS Service under the same tenant.
- An issuer identity — Either a DID or an X.509 certificate (choose per the format table below).
The table below shows which issuer identification method (DID or X.509 certificate) is supported for each credential format:
| Format | DIDs | X.509 Certificates |
|---|---|---|
| JWT (W3C) | ✓ | ✓ |
| SD-JWT (W3C) | ✓ | ✓ |
| SD-JWT VC (IETF) | ✓ | ✓ |
| ISO mDoc | – | ✓ |
✓ supported · – not available
Create a Profile
Endpoint: POST /v2/{target}.{profileId}/issuer-service-api/credentials/profiles | API Reference
The new profile's own ID is the last path segment of the target (like service creation), i.e. {target}.{profileId} — here waltid.tenant1.issuer1.profile-abc123.
Example Request
curl -X 'POST' \
'https://{orgID}.enterprise-sandbox.waltid.dev/v2/{target}.profile-abc123/issuer-service-api/credentials/profiles' \
-H 'accept: application/json' \
-H 'Authorization: Bearer {yourToken}' \
-H 'Content-Type: application/json' \
-d '{
"name": "Open Badge Credential Profile",
"credentialConfigurationId": "OpenBadgeCredential_jwt_vc_json",
"issuerKeyId": "waltid.tenant1.kms1.key1",
"issuerDid": "did:key:z6MkjoRhq1jSNJdLiruSXrFFxagqrztZaXHqHGUTKJbcNywp",
"w3cVersion": "W3CV2",
"credentialData": {
"@context": [
"https://www.w3.org/ns/credentials/v2",
"https://purl.imsglobal.org/spec/ob/v3p0/context-3.0.3.json",
"https://purl.imsglobal.org/spec/ob/v3p0/extensions.json"
],
"type": ["VerifiableCredential", "OpenBadgeCredential"],
"issuer": {
"type": ["Profile"],
"name": "Jobs for the Future (JFF)",
"url": "https://www.jff.org/",
"image": "https://w3c-ccg.github.io/vc-ed/plugfest-1-2022/images/JFF_LogoLockup.png"
},
"credentialSubject": {
"type": ["AchievementSubject"],
"achievement": {
"id": "https://example.com/achievements/21st-century-skills/teamwork",
"type": ["Achievement"],
"criteria": {
"narrative": "Team members are nominated for this badge by their peers and recognized upon review by Example Corp management."
},
"description": "This badge recognizes the development of the capacity to collaborate within a group environment.",
"name": "Teamwork"
}
},
"credentialSchema": [
{
"id": "https://purl.imsglobal.org/spec/ob/v3p0/schema/json/ob_v3p0_achievementcredential_schema.json",
"type": "1EdTechJsonSchemaValidator2019"
}
]
},
"mapping": {
"id": "<uuid>",
"issuer": { "id": "<issuerDid>" },
"credentialSubject": { "id": "<subjectDid>" },
"validFrom": "<timestamp>",
"validUntil": "<timestamp-in:365d>"
}
}'
Path Parameters
- orgID: String (required) - Your organization ID, e.g.
test.enterprise-sandbox.waltid.dev. - target: String (required) - The issuer service path followed by the new profile's own ID as the final segment,
{organizationID}.{tenantID}.{issuerServiceID}.{profileId}, e.g.waltid.tenant1.issuer1.profile-abc123. The{profileId}you choose here becomes the profile's ID.
Header Parameters
- Authorization: String (required) - Bearer token for Enterprise Stack authentication. Format:
Bearer {token}.
Body Parameters
- name: String (required) - A human-readable name for the profile.
- credentialConfigurationId: String (required) - The credential configuration ID this profile issues. Must match a credential configuration declared on your issuer service.
- issuerKeyId: resourceIdentifier (required) - The key ID of a key stored in a KMS service under the same tenant, e.g.
waltid.tenant1.kms1.key1. - credentialData: Object (required) - The credential data template. Structure depends on the credential format.
- issuerDid: String (optional) - The DID of the issuer. Not supported for mDocs.
- x5Chain: Array (optional) - X.509 certificate chain for signing (required for mDoc). The first certificate is the issuer's; provide the full chain if required. Each entry is a descriptor object
{ "type": "pem-encoded-x509-certificate-descriptor", "pemEncodedCertificate": "<PEM>" }. (A bare PEM string is also accepted for backwards compatibility, but the API always stores and returns the object form.) - mapping: Object (optional) - Data mapping with data functions for dynamic value insertion at claim time.
- selectiveDisclosure: Object (optional) - Which SD-JWT claims a holder can selectively disclose, plus optional decoy configuration. Applies to SD-JWT VC and W3C SD-JWT credentials.
- idTokenClaimsMapping: Object (optional) - Maps claims from external IdP tokens to credential data fields using JSONPath. See ID Token Claims Mapping.
- mDocNameSpacesDataMappingConfig: Object (optional) - Type conversion configuration for mDoc credentials. See mDoc Data Mapping.
- authorizedTransactionDataTypes: Array of Strings (optional) - OpenID4VP transaction-data types this mDoc's device key may sign. Embedded in the MSO as
KeyAuthorizationsat issuance. See Authorized Transaction Data Types. - credentialStatus: Object (optional) - Configuration for credential status (revocation/suspension). See Credential Status.
- notifications: Object (optional) - Webhook notification settings. See Notifications.
- w3cVersion: String (optional) - W3C data model version of the issued credential. Either
W3CV11for VCDM v1.1 orW3CV2for v2.The
w3cVersionparameter controls the format of the issued credential. When set toW3CV2, the service automatically applies the correct VCDM v2@context(https://www.w3.org/ns/credentials/v2) and usesvalidFrom/validUntilin place ofissuanceDate/expirationDate, regardless of what is provided incredentialData.
Example Response
{
"profileId": "profile-abc123",
"name": "Open Badge Credential Profile",
"version": 1,
"credentialConfigurationId": "OpenBadgeCredential_jwt_vc_json",
"issuerKeyId": "waltid.tenant1.kms1.key1",
"issuerDid": "did:key:z6MkjoRhq1jSNJdLiruSXrFFxagqrztZaXHqHGUTKJbcNywp",
"credentialData": { "...": "..." },
"mapping": { "...": "..." },
"w3cVersion": "W3CV2",
"createdAt": 1704067200000,
"updatedAt": 1704067200000
}
The service stores and echoes the full profile object; credentialData and mapping are elided above for brevity. Format-specific fields are included when set — w3cVersion for W3C, selectiveDisclosure for SD-JWT VC, mDocNameSpacesDataMappingConfig / authorizedTransactionDataTypes for mDoc.
Response Fields
- profileId: String - The profile's own ID — the last path segment you chose, e.g.
profile-abc123. To address the profile elsewhere (e.g. as an offer target), use the full path{target}.{profileId}. - version: Integer - The profile version (starts at 1, increments on update).
- createdAt / updatedAt: Long - Unix timestamps (ms).
Response Codes
201— Profile created successfully.400— Invalid request body.401— Invalid or missing authentication token.
🎉 You've created a credential profile.
Advanced Configuration
ID Token Claims Mapping
When using the authorization code flow with an external IdP, you can map claims from the ID token to credential data fields:
{
"idTokenClaimsMapping": {
"$.family_name": "$.credentialSubject.familyName",
"$.given_name": "$.credentialSubject.givenName",
"$.email": "$.credentialSubject.email"
}
}
The keys are JSONPath expressions pointing to claims in the ID token, and the values are JSONPath expressions pointing to fields in the credential data.
mDoc Data Mapping
For mDoc/mDL credentials, you need to specify type conversions for CBOR encoding:
{
"mDocNameSpacesDataMappingConfig": {
"org.iso.18013.5.1": {
"entriesConfigMap": {
"birth_date": { "type": "string", "conversionType": "stringToFullDate" },
"issue_date": { "type": "string", "conversionType": "stringToFullDate" },
"expiry_date": { "type": "string", "conversionType": "stringToFullDate" },
"portrait": { "type": "string", "conversionType": "base64StringToByteString" }
}
}
}
}
Available Conversion Types:
| Conversion Type | Description |
|---|---|
stringToFullDate | Converts ISO date string (e.g. 2024-01-15) to CBOR full-date (tag 1004). |
stringToTDate | Converts ISO timestamp string to CBOR tdate (tag 0). |
base64StringToByteString | Converts standard base64-encoded string to CBOR byte string. |
base64UrlStringToByteString | Converts base64url-encoded string to CBOR byte string. |
Authorized Transaction Data Types
For mso_mdoc credentials that must later present OpenID4VP transaction_data, the device key can only device-sign types that appear in the MSO's KeyAuthorizations. Issuer2 embeds that grant from authorizedTransactionDataTypes.
{
"authorizedTransactionDataTypes": ["urn:eudi:sca:payment:1"]
}
What the issuer writes into the MSO for each listed type:
- Namespace = the transaction-data type string itself (walt.id convention, matching what the wallet presenter emits)
- Data elements =
transaction_data_hashandtransaction_data_hash_alg - No blanket
nameSpacesauthorization — only those hash elements are granted
Blank entries are dropped, duplicates collapsed. If the list is null or empty after filtering, no KeyAuthorizations are emitted.
Presentation of an unlisted type is rejected for that mDoc. Register the same type in transaction-data-profiles.conf, and list it here on the issuing profile.
This field applies to mDoc (mso_mdoc) only. SD-JWT VC transaction-data binding uses the KB-JWT and does not consume authorizedTransactionDataTypes.
Example — mDoc profile that authorizes EUDI TS-12 SCA payment transaction data:
{
"name": "SCA Payment Card Profile",
"credentialConfigurationId": "eu.europa.ec.eudi.sca.payment_card.1",
"issuerKeyId": "waltid.tenant1.kms1.key1",
"x5Chain": [
{
"type": "pem-encoded-x509-certificate-descriptor",
"pemEncodedCertificate": "-----BEGIN CERTIFICATE-----\nMIIB...\n-----END CERTIFICATE-----\n"
}
],
"credentialData": {
"eu.europa.ec.eudi.sca.payment_card.1": {
"card_scheme": "visa",
"card_last4": "4242",
"card_holder_name": "Jane Doe"
}
},
"authorizedTransactionDataTypes": ["urn:eudi:sca:payment:1"]
}
Credential Status
Configure credential status for revocation/suspension support:
{
"credentialStatus": {
"statusCredentialConfig": "waltid.tenant1.credentialstatus.config1",
"initialStatus": "0x0"
}
}
- statusCredentialConfig: resourceIdentifier - Reference to a credential status configuration in the Credential Status Service.
- initialStatus: String - Initial status value (e.g.
"0x0"for valid).
To use credentialStatus, make sure the credential status service is added as a dependency of the Issuer2 service.
Different credential formats support different status list types:
- W3C JWT/SD-JWT: Bitstring Status List, StatusList2021
- SD-JWT VC (IETF): Token Status List
- mDoc: Token Status List
Automatic rollover: If the referenced credential status service has autoRollover enabled, new status lists are created automatically when capacity thresholds are reached. This is transparent to the issuer — you can keep using the same statusCredentialConfig reference. Learn more about automatic rollover.
Example Profiles
SD-JWT VC Profile
{
"name": "Identity Credential Profile",
"credentialConfigurationId": "identity_credential_vc+sd-jwt",
"issuerKeyId": "waltid.tenant1.kms1.key1",
"issuerDid": "did:key:z6MkjoRhq1jSNJdLiruSXrFFxagqrztZaXHqHGUTKJbcNywp",
"credentialData": {
"given_name": "John",
"family_name": "Doe",
"birthdate": "1990-01-15"
},
"selectiveDisclosure": {
"fields": {
"birthdate": { "sd": true }
}
},
"mapping": {
"iat": "<timestamp-seconds>",
"exp": "<timestamp-in-seconds:365d>"
}
}
mDoc Profile with PEM X.509 Certificate
{
"name": "Photo ID Profile",
"credentialConfigurationId": "org.iso.23220.photoid.1",
"issuerKeyId": "waltid.tenant1.kms1.key1",
"x5Chain": [
{
"type": "pem-encoded-x509-certificate-descriptor",
"pemEncodedCertificate": "-----BEGIN CERTIFICATE-----\nMIIB...\n-----END CERTIFICATE-----\n"
}
],
"credentialData": {
"org.iso.23220.photoid.1": {
"given_name_unicode": "John",
"family_name_unicode": "Doe",
"birth_date": "1990-01-15",
"issuance_date": "2024-01-01",
"expiry_date": "2029-01-01",
"portrait": "base64-encoded-image-data"
}
},
"mDocNameSpacesDataMappingConfig": {
"org.iso.23220.photoid.1": {
"entriesConfigMap": {
"birth_date": { "type": "string", "conversionType": "stringToFullDate" },
"issuance_date": { "type": "string", "conversionType": "stringToFullDate" },
"expiry_date": { "type": "string", "conversionType": "stringToFullDate" },
"portrait": { "type": "string", "conversionType": "base64StringToByteString" }
}
}
}
}
mDoc Profile with X.509 Store Stored Certificate
{
"name": "Photo ID Profile",
"credentialConfigurationId": "org.iso.23220.photoid.1",
"issuerKeyId": "waltid.tenant1.kms1.key1",
"x5Chain": [
{
"type": "x509-store-stored-certificate-descriptor",
"storedCertificateId": "waltid.tenant1.x509-store.issuer-certificate"
}
],
"credentialData": {
"org.iso.23220.photoid.1": {
"given_name_unicode": "John",
"family_name_unicode": "Doe",
"birth_date": "1990-01-15",
"issuance_date": "2024-01-01",
"expiry_date": "2029-01-01",
"portrait": "base64-encoded-image-data"
}
},
"mDocNameSpacesDataMappingConfig": {
"org.iso.23220.photoid.1": {
"entriesConfigMap": {
"birth_date": { "type": "string", "conversionType": "stringToFullDate" },
"issuance_date": { "type": "string", "conversionType": "stringToFullDate" },
"expiry_date": { "type": "string", "conversionType": "stringToFullDate" },
"portrait": { "type": "string", "conversionType": "base64StringToByteString" }
}
}
}
}
Profile with Notifications
{
"name": "Notified Credential Profile",
"credentialConfigurationId": "OpenBadgeCredential_jwt_vc_json",
"issuerKeyId": "waltid.tenant1.kms1.key1",
"issuerDid": "did:key:z6MkjoRhq1jSNJdLiruSXrFFxagqrztZaXHqHGUTKJbcNywp",
"credentialData": { "...": "..." },
"notifications": {
"webhook": {
"url": "https://your-server.com/webhook/issuance",
"bearerToken": "your-secret-token"
}
}
}
Next Steps
- Manage Profiles – View, update, and delete profiles.
- Create Credential Offers – Use your profile to create credential offers.
