In the realm of Verifiable Credentials, each credential must be associated with a schema. The credential’s schema is referred to as “type”.

Credential types outline the attributes and their respective data types that the credential contains. The purpose of types is to ensure the credential’s authenticity. Types allow you to specify the attributes you are interested in certifying and act as a protective measure, preventing the addition of unauthorized attributes and, as a result, the tampering of the Verifiable Credential.

It’s important to note that all credentials within a single template will share the same type. Trying to issue or verify a credential with different field names or types will result in an error.

By adhering to this structure, we maintain the integrity and verifiability of the credentials, ensuring they serve their purpose effectively.

Example Types

Credentials play a crucial role in verifying and validating various aspects of identity, achievement, and authorization. Below are some examples of credential types you can create and manage through Crossmint:

Proof of Employment

  • Purpose: Issued to individuals that want to prove their employment.
  • Name: ProofOfEmployment
ProofOfEmployment {
    position: string;
    department: string;
    startDate: string;
}

The payload used to create this type is the following:

{
    "$schema": "https://json-schema.org/draft/2020-12/schema",
    "title": "Proof of Employment",
    "description": "Schema for verifying employment details",
    "type": "object",
    "properties": {
        "credentialSubject": {
            "type": "object",
            "properties": {
                "position": {
                    "type": "string"
                },
                "department": {
                    "type": "string"
                },
                "startDate": {
                    "type": "string"
                }
            },
            "required": ["position", "department", "startDate"],
            "additionalProperties": false
        }
    }
}

To reference this example type in your credential template definition, use crossmint:bfb292e7-2700-4924-9213-478f3d71f2d8:ProofOfEmployment.

Course Completion Certificates

  • Purpose: Issued to students upon the successful completion of a course. The certificate may indicate that the student has mastered a specific skill or knowledge.
  • Type: CourseCompletionCertificate
CourseCompletionCertificate {
    course: string;
    grade: string;
}

If you want to use this example type in your credential template definition, you can reference it as crossmint:bfb292e7-2700-4924-9213-478f3d71f2d8:CourseCompletionCertificate.

Membership Credentials

  • Purpose: Provided to individuals who are members of a specific organization or club. The certificate may grant access to exclusive resources and events.
  • Name: Membership
Membership {
  organizationName: string;
  membershipType: string;
  issueDate: string;
  benefits: string[];
  status: string;
}

If you want to use this example type in your credential template definition, you can reference it as crossmint:bfb292e7-2700-4924-9213-478f3d71f2d8:Membership.

Event Participation Certificates

  • Purpose: Issued to individuals who attend or participate in specific events.
  • Name: EventParticipation
EventParticipation {
  eventName: string;
  eventDate: string;
  location: string;
  description: string;
}

If you want to use this example type in your credential template definition, you can reference it as crossmint:bfb292e7-2700-4924-9213-478f3d71f2d8:EventParticipation.

Types Creation Quickstart

This example creates a custom type, CourseCompletionCertificate, for a credential that represents a course completion. The credential will contain two fields: course and passed.

Copy the createType.js file in the tab above, add your API key to the X-API-KEY header (or create one if you haven’t already) and run via node.

node createType.js

The response, shown below, includes the credential type name.

Response
{
    "id": "crossmint:bfb292e7-2700-4924-9213-478f3d71f2d8:CourseCompletionCertificate", // Internal type id
    "typeSchema": {
        "$schema": "https://json-schema.org/draft/2020-12/schema",
        "title": "Course completion", // Veryfiable credential `type` name.
        "description": "Describes the course completed and the assigned grade",
        "type": "object",
        "properties": {
            "credentialSubject": {
                "type": "object",
                "properties": {
                    "course": {
                        "type": "string"
                    },
                    "grade": {
                        "type": "string"
                    },
                    "id": {
                        "type": "string"
                    }
                },
                "required": ["course", "grade"],
                "additionalProperties": false
            }
        },
        "$id": "https://staging.crossmint.com/api/v1-alpha1/credentials/types/crossmint:bfb292e7-2700-4924-9213-478f3d71f2d8:CourseCompletionCertificate" // External schema URI
    }
}

The type id defined will be used when you create your credential template.

You can also utilize the POST /credentials/types/ endpoint to generate a random uuid for the new credential type.

For internal use within Crossmint, reference the type using id. The $id will be included as the credentials schema by Crossmint but should not be used to reference the type in Crossmint APIs.

Example of a credentials using the type "crossmint:bfb292e7-2700-4924-9213-478f3d71f2d8:CourseCompletionCertificate" just created.

Example Credential
 {
    "id": "urn:uuid:820b09e8-bd6d-4680-b2b1-b564169fde8a",
    "credentialSubject": {
        "course": "Math",
        "grade": "A",
        "id": "did:polygon-amoy:0x1B887669437644aA348c518844660ef8d63bd643"
    },
    "nft": {
        "tokenId": "7",
        "chain": "polygon-amoy",
        "contractAddress": "0xb14Bf8EEa68026a2746350059389Bd119CFB8E29"
    },
    "issuer": {
        "id": "did:polygon-amoy:0xd9d8BA9D5956f78E02F4506940f42ac2dAB9DABd"
    },
    "type": [
        "VerifiableCredential",
        "Course completion" // Schema.title
    ],
    "validFrom": "2024-11-19T18:41:30.503Z",
    "@context": [
        "https://www.w3.org/ns/credentials/v2"
    ],
    "credentialSchema": {
        "id": "https://staging.crossmint.com/api/v1-alpha1/credentials/types/crossmint:bfb292e7-2700-4924-9213-478f3d71f2d8:CourseCompletionCertificate", // Schema.$id
        "type": "JsonSchema"
    },
    "proof": { ... }
}

Types Creation Deep Dive

In the realm of Verifiable Credentials, types are defined using the JSON schema. For more details, refer to the W3C VC JSON Schema. When calling the create type API an invalid JSON schema will result in an error.

Type schema structure

Below is an example of a JSON schema structure for defining a credential type:

Example Schema Payload
{
    "$schema": "https://json-schema.org/draft/2020-12/schema",
    "title": "Example nested schema",
    "description": "A schema capturing a human name and a nested `additionalInfo` object",
    "type": "object",
    "properties": {
        "credentialSubject": {
            "type": "object",
            "properties": {
                "firstName": {
                    "type": "string"
                },
                "id": {
                    // This will be added automatically, is not necessary
                    "type": "string"
                },
                "additionalInfo": {
                    "type": "object",
                    "properties": {
                        "age": {
                            "type": "integer"
                        },
                        "isActive": {
                            "type": "boolean"
                        },
                        "tags": {
                            // Optional, therefore is not added to `required`
                            "type": "array",
                            "items": {
                                "type": "string"
                            }
                        }
                    },
                    "required": ["age", "isActive"],
                    "additionalProperties": false // Needs to be repeated for each nested object
                }
            },
            "required": ["firstName", "additionalInfo"],
            "additionalProperties": false
        }
    }
}

Explanation of Each Part:

  • $schema: This should always be set to “https://json-schema.org/draft/2020-12/schema”.
  • $id: This field should NOT be defined, will be generated by Crossmint and returned in the response.
  • title: Represents the name of the type.
  • description: A brief description of the schema.
  • type: Must be set to “object”.
  • properties: Must include credentialSubject as an object.

Important Notes:

  • The credential subject is the section that needs to be defined. Any field or nested field can be added, as long as it is valid JSON schema.
  • The credentialSubject.properties.id will be automatically added with the type “string”, this is used to specify the wallet and therefore the identity of the subject.
  • additionalProperties should always be set to false to prevent unauthorized fields from being added.
  • All specified fields should be marked as required unless they are optional. This ensures that missing fields will trigger an error during schema validation.
  • additionalProperties and required apply only at the level they are specified. For nested objects, these need to be repeated.

Type import

If you already have a JSON schema type, you can easily import it by calling the same endpoint with the following structure:

importType.js
const payload = {
    $id: "https://raw.githubusercontent.com/decentralized-identity/credential-schemas/main/schemas/ExampleEntity/ExampleNameSchema.json",
};
const options = {
    method: "POST",
    headers: {
        "X-API-KEY": "YOUR_API_KEY",
        "Content-Type": "application/json",
    },
    body: JSON.stringify(schema),
};

fetch(`https://staging.crossmint.com/api/unstable/credentials/types`, options)
    .then((response) => response.json())
    .then((response) => console.log(JSON.stringify(response)))
    .catch((err) => console.error(err));
Response
{
    "id": "crossmint:e62564a7-06eb-4f65-b389-eb3b7a4f6f98:10ede8a6",
    "typeSchema": {
        "$id": "https://raw.githubusercontent.com/decentralized-identity/credential-schemas/main/schemas/ExampleEntity/ExampleNameSchema.json",
        "$schema": "https://json-schema.org/draft/2020-12/schema",
        "title": "Example Name schema",
        "description": "A schema capturing a human name",
        "type": "object",
        "properties": {
            "credentialSubject": {
                "type": "object",
                "properties": {
                    "firstName": {
                        "type": "string"
                    },
                    "id": {
                        "type": "string"
                    }
                },
                "required": ["firstName"],
                "additionalProperties": false
            }
        }
    }
}

Important Notes for Import:

  • All notes for type creation apply here as well.
  • credentialSubject.properties.id will not be added for imported schemas. If the original schema does not include this specification, the resulting credentials will not include the user wallet in the subject.id. To know the subject of a credential, checking the NFT owner will be necessary.

To follow along and test the API calls use a tool like Postman or our API playground.