Template Service¶
The Template Service allows you to manage and search Credential Templates.
Create Template¶
Creates a new credential template.
The name
of a template must be unique within your ecosystem, and cannot be changed -- it is used to derive the URI of the template itself.
The title
and description
parameters (for the template itself, as well as for any of its fields) should be human-readable strings. They should describe the credentials issued by the template, not the template itself (for example, a good title for a medical license template would simply be "Medical License", not "Medical License Template").
field_ordering
may be used to specify the order in which fields are rendered when displaying a credential, and to categorize fields into logical sections. This is used for display only, and has no bearing on working with credentials as an issuer or verifier.
trinsic template create --name 'My Credential' --fields-data '{\"field1\":{}}'
const createRequest: CreateCredentialTemplateRequest = {
name: "An Example Credential",
title: "Example Credential",
description: "A credential for Trinsic's SDK samples",
allowAdditionalFields: false,
fields: {
firstName: { title: "First Name", description: "Given name of holder" },
lastName: { title: "Last Name", description: "Surname of holder", optional: true },
age: { title: "Age", description: "Age in years of holder", type: FieldType.NUMBER }
},
fieldOrdering: {
firstName: { order: 0, section: "Name" },
lastName: { order: 1, section: "Name" },
age: { order: 2, section: "Miscellaneous" }
},
appleWalletOptions: {
primaryField: "firstName",
secondaryFields: ["lastName"],
auxiliaryFields: ["age"]
}
};
const createResponse = await trinsic.template().create(createRequest);
CreateCredentialTemplateRequest createRequest = new()
{
Name = "An Example Credential",
Title = "Example Credential",
Description = "A credential for Trinsic's SDK samples",
AllowAdditionalFields = false,
Fields =
{
{ "firstName", new() { Title = "First Name", Description = "Given name of holder" } },
{ "lastName", new() { Title = "Last Name", Description = "Surname of holder", Optional = true } },
{ "age", new() { Title = "Age", Description = "Age in years of holder", Type = FieldType.Number } }
},
FieldOrdering =
{
{ "firstName", new() { Order = 0, Section = "Name" } },
{ "lastName", new() { Order = 1, Section = "Name" } },
{ "age", new() { Order = 2, Section = "Miscellanous" } }
},
AppleWalletOptions = new()
{
PrimaryField = "firstName",
SecondaryFields = { "lastName" },
AuxiliaryFields = { "age" }
}
};
var template = await trinsic.Template.CreateAsync(createRequest);
create_request = CreateCredentialTemplateRequest(
name="An Example Credential",
title="Example Credential",
description="A credential for Trinsic's SDK samples",
allow_additional_fields=False,
fields={
"firstName": TemplateField(
title="First Name", description="Given name of holder"
),
"lastName": TemplateField(
title="Last Name", description="Surname of holder", optional=True
),
"age": TemplateField(
title="Age", description="Age in years of holder", type=FieldType.NUMBER
),
},
field_ordering={
"firstName": FieldOrdering(order=0, section="Name"),
"lastName": FieldOrdering(order=1, section="Name"),
"age": FieldOrdering(order=2, section="Miscellaneous"),
},
apple_wallet_options=AppleWalletOptions(
primary_field="firstName",
secondary_fields=["lastName"],
auxiliary_fields=["age"],
),
)
create_response = await trinsic_service.template.create(request=create_request)
templateRequest := &template.CreateCredentialTemplateRequest{
Name: "An Example Credential",
Title: "Example Credential",
Description: "A credential for Trinsic's SDK samples",
AllowAdditionalFields: false,
Fields: map[string]*template.TemplateField{
"firstName": {
Title: "First Name",
Description: "Given name of holder",
},
"lastName": {
Title: "Last Name",
Description: "Surname of holder",
Optional: true,
},
"age": {
Title: "Age",
Description: "Age in years of holder",
Type: template.FieldType_NUMBER,
},
},
FieldOrdering: map[string]*template.FieldOrdering{
"firstName": {Order: 0, Section: "Name"},
"lastName": {Order: 1, Section: "Name"},
"age": {Order: 2, Section: "Miscellaneous"},
},
AppleWalletOptions: &template.AppleWalletOptions{
PrimaryField: "firstName",
SecondaryFields: []string{"lastName"},
AuxiliaryFields: []string{"age"},
},
}
templateResponse, err := trinsic.Template().Create(context.Background(), templateRequest)
var templateRequest =
CreateCredentialTemplateRequest.newBuilder()
// Set metadata
.setName("An Example Credential" + UUID.randomUUID())
.setTitle("Example Credential")
.setDescription("A credential for Trinsic's SDK samples")
.setAllowAdditionalFields(false)
// Construct fields
.putFields(
"firstName",
TemplateField.newBuilder()
.setTitle("First Name")
.setDescription("Given name of holder")
.build())
.putFields(
"lastName",
TemplateField.newBuilder()
.setTitle("Last Name")
.setDescription("Surname of holder")
.setOptional(true)
.build())
.putFields(
"age",
TemplateField.newBuilder()
.setTitle("Age")
.setDescription("Age in years of holder")
.setType(FieldType.NUMBER)
.build())
// Specify ordering and categorization of fields for rendering of credential
.putFieldOrdering(
"firstName", FieldOrdering.newBuilder().setOrder(0).setSection("Name").build())
.putFieldOrdering(
"lastName", FieldOrdering.newBuilder().setOrder(1).setSection("Name").build())
.putFieldOrdering(
"age", FieldOrdering.newBuilder().setOrder(2).setSection("Miscellaneous").build())
// Specify Apple Wallet configuration
.setAppleWalletOptions(
AppleWalletOptions.newBuilder()
.setPrimaryField("firstName")
.addSecondaryFields("lastName")
.addAuxiliaryFields("age")
.build())
.build();
var template = trinsic.template().create(templateRequest).get();
fields
name
. If not provided, this will be auto-generated.CreateCredentialTemplateRequest
Update Template¶
Updates a template's display metadata, such as its human-readable title/description.
This call cannot be used to update templates in a way that might invalidate previously-issued credentials: fields cannot be added, removed, or renamed, but their title
and description
properties may be updated.
In order to leave a property unchanged (for example, if you wish to change description
but not title
), simply leave it unspecified (don't set it to an empty string/object). This applies to fields as well: any field not specified in fields
will remain unchanged.
Not yet supported
import {
CheckStatusRequest,
CreateCredentialTemplateResponse,
TrinsicService,
UpdateCredentialTemplateRequest,
UpdateStatusRequest,
} from "../src";
// @ts-ignore
import templateCertFrame from "./data/credential-template-frame.json";
import {getTestServerOptions, setTestTimeout} from "./env";
import {
createCredentialTemplateTest,
createRequiredTestObjects,
issueCredentialFromTemplate,
verifyCredential,
} from "./CredentialTemplateShared";
import {CreateCredentialTemplateRequest, FieldType} from "../lib";
const { nameField, numberOfBags, dateOfBirth, isVaccinated } =
createRequiredTestObjects();
let trinsic: TrinsicService;
let createdTemplate: CreateCredentialTemplateResponse;
describe("Demo: Credential Templates", () => {
setTestTimeout();
beforeAll(async () => {
trinsic = new TrinsicService(getTestServerOptions());
await trinsic.provider().createEcosystem({});
});
it("should run create and delete credential templates", async () => {
createdTemplate = await createCredentialTemplateTest(trinsic);
const fieldsMap = createdTemplate.data?.fields!;
expect(fieldsMap["name"]).toEqual(nameField);
expect(fieldsMap["numberOfBags"]).toEqual(numberOfBags);
expect(fieldsMap["dateOfBirth"]).toEqual(dateOfBirth);
expect(fieldsMap["vaccinated"]).toEqual(isVaccinated);
let deletedTemplate = await trinsic
.template()
.delete({ id: createdTemplate.data?.id ?? "" });
console.log(deletedTemplate);
});
it("Issue Credential From Template", async () => {
let response = JSON.parse(
(await issueCredentialFromTemplate(trinsic)).documentJson!
);
expect(response?.issuer).not.toBeNull();
expect(response?.id).not.toBeNull();
expect(response?.credentialSubject?.name).toBe("Alice");
expect(response?.credentialSubject?.numberOfBags).toBe(2);
expect(
new Date(response?.credentialSubject?.dateOfBirth).toISOString()
).toBe(new Date("1/1/2000").toISOString());
expect(response?.credentialSubject?.vaccinated).toBe(true);
});
it("Verify Credential Issued from Template", async () => {
let response = await verifyCredential(
trinsic,
JSON.stringify(templateCertFrame)
);
expect(response).toBeTruthy();
});
it("Update Revocation Status for Template", async () => {
try {
// checkCredentialStatus() {
let checkStatusResponse = await trinsic
.credential()
.checkStatus(CheckStatusRequest.fromPartial({}));
// }
} catch {
// This is okay as an example
}
try {
// updateCredentialStatus() {
let updateStatusResponse = await trinsic
.credential()
.updateStatus(UpdateStatusRequest.fromPartial({}));
// }
} catch {
// This is okay as an example
}
});
});
UpdateCredentialTemplateRequest updateRequest = new() {
Id = templateId,
Title = "New Title",
Description = "New Description",
Fields = {
{ "firstName", new() { Title = "New title for firstName" } },
{ "lastName", new() { Description = "New description for lastName" } }
},
FieldOrdering =
{
{ "age", new() { Order = 0, Section = "Misc" } },
{ "firstName", new() { Order = 1, Section = "Full Name" } },
{ "lastName", new() { Order = 2, Section = "Full Name" } },
},
AppleWalletOptions = new()
{
PrimaryField = "age",
SecondaryFields = { "firstName", "lastName" }
}
};
var updatedTemplate = await trinsic.Template.UpdateAsync(updateRequest);
update_request = UpdateCredentialTemplateRequest(
id=template_id,
title="New Title",
description="New Description",
fields={
"firstName": TemplateFieldPatch(title="New title for firstName"),
"lastName": TemplateFieldPatch(description="New description for lastName"),
},
field_ordering={
"age": FieldOrdering(order=0, section="Misc"),
"firstName": FieldOrdering(order=1, section="Full Name"),
"lastName": FieldOrdering(order=2, section="Full Name"),
},
apple_wallet_options=AppleWalletOptions(
primary_field="age", secondary_fields=["firstName", "lastName"]
),
)
update_response = await trinsic_service.template.update(request=update_request)
var newTemplateTitle = "New Title"
var newTemplateDescription = "New Description"
var newFirstNameTitle = "New title for firstName"
var newLastNameDescription = "New description for lastName"
updateRequest := &template.UpdateCredentialTemplateRequest{
Id: templateId,
Title: &newTemplateTitle,
Description: &newTemplateDescription,
Fields: map[string]*template.TemplateFieldPatch{
"firstName": {Title: &newFirstNameTitle},
"lastName": {Description: &newLastNameDescription},
},
FieldOrdering: map[string]*template.FieldOrdering{
"age": {Order: 0, Section: "Misc"},
"firstName": {Order: 1, Section: "Full Name"},
"lastName": {Order: 2, Section: "Full Name"},
},
AppleWalletOptions: &template.AppleWalletOptions{
PrimaryField: "age",
SecondaryFields: []string{"firstName", "lastName"},
},
}
updateResponse, err := trinsic.Template().Update(context.Background(), updateRequest)
var updateRequest =
UpdateCredentialTemplateRequest.newBuilder()
.setId(templateId)
// Specify new title and description for the template
.setTitle("New Title")
.setDescription("New Description")
// Update title/description for a few fields
.putFields(
"firstName",
TemplateFieldPatch.newBuilder().setTitle("New title for firstName").build())
.putFields(
"lastName",
TemplateFieldPatch.newBuilder()
.setDescription("New description for lastName")
.build())
// Specify new ordering / categorization for template fields
.putFieldOrdering(
"age", FieldOrdering.newBuilder().setOrder(0).setSection("Misc").build())
.putFieldOrdering(
"firstName", FieldOrdering.newBuilder().setOrder(1).setSection("Full Name").build())
.putFieldOrdering(
"lastName", FieldOrdering.newBuilder().setOrder(2).setSection("Full Name").build())
// Specify new Apple Wallet configuration
.setAppleWalletOptions(
AppleWalletOptions.newBuilder()
.setPrimaryField("age")
.addSecondaryFields("firstName")
.addSecondaryFields("lastName")
.build())
.build();
var updatedTemplate = trinsic.template().update(updateRequest).get();
UpdateCredentialTemplateRequest
Get Template¶
Fetches a template definition by id
.
trinsic template get --id <TEMPLATE_ID>
let getTemplateResponse = await trinsic.template().get(GetCredentialTemplateRequest.fromPartial({
id: "id"
}));
var getTemplateResponse = await trinsic.Template.GetAsync(new() { Id = template.Data.Id });
get_template_response = await trinsic_service.template.get(
request=GetCredentialTemplateRequest(id=template.data.id)
)
getResponse, err := trinsic.Template().Get(context.Background(), &template.GetCredentialTemplateRequest{Id: templateResponse.Data.Id})
var getResponse =
trinsic
.template()
.get(GetCredentialTemplateRequest.newBuilder().setId(templateId).build())
.get();
GetCredentialTemplateRequest
Delete Template¶
Deletes a credential template by id
.
trinsic template delete --id <TEMPLATE_ID>
var deleteTemplateResponse = await trinsic.Template.DeleteAsync(new() { Id = template.Data.Id });
delete_template_response = await trinsic_service.template.delete(
request=DeleteCredentialTemplateRequest(id=template.data.id)
)
deleteResponse, err := trinsic.Template().Delete(context.Background(), &template.DeleteCredentialTemplateRequest{Id: templateResponse.Data.Id})
var deleteResponse =
trinsic
.template()
.delete(DeleteCredentialTemplateRequest.newBuilder().setId(templateId).build())
.get();
DeleteCredentialTemplateRequest
Search Templates¶
Searches all templates defined in the current ecosystem, and a continuation_token
to paginate large result sets.
If no query
is specified, this call by default returns the first 100 templates.
trinsic wallet search \
--query "SELECT * FROM c"
let searchTemplateResponse = await trinsic.template().search(
SearchCredentialTemplatesRequest.fromPartial({
query: "Select * from c",
})
);
var searchTemplateResponse = await trinsic.Template.SearchAsync(new() { Query = "SELECT * FROM c" });
search_template_response = await trinsic_service.template.search(
request=SearchCredentialTemplatesRequest(query="SELECT * FROM c")
)
searchResponse, err := trinsic.Template().Search(context.Background(), &template.SearchCredentialTemplatesRequest{Query: "SELECT * FROM c"})
var searchResponse =
trinsic
.template()
.search(
SearchCredentialTemplatesRequest.newBuilder()
.setQuery("SELECT * FROM c WHERE c.id = '" + templateId + "'")
.build())
.get();
SELECT * FROM c WHERE c.name = 'Diploma'
SearchCredentialTemplatesResponse
if more data is available for querySearchCredentialTemplatesRequest
continuation_token
SearchCredentialTemplatesRequest
Advanced Search¶
The Search endpoint supports SQL queries through the query
parameter.
This allows for arbitrary query predicates, as well as more advanced functionality -- such as modifying the output format.
Schema¶
Any table name may be used in your query (we use c
here) -- it doesn't matter what it is.
Name | Type | Description |
---|---|---|
id | string | Corresponds to the id returned when template was created |
type | string | Always VerifiableCredential |
ecosystemId | string | ID of ecosystem in which template resides |
createdBy | string | ID of account which defined the template |
name | string | Name provided during template creation |
schemaUri | string | HTTPS URL pointing to JSON Schema generated by Trinsic for this template |
contextUri | string | HTTPS URL pointing to JSON-LD Context generated by Trinsic for this template |
version | int | Version of template; increments whenever template is modified. |
fields | object | JSON Object representing the template's fields |
Note that fields
is an object, not a string; thus, any of its sub-fields may be queried against.
More Info
This endpoint works very similarly to querying Wallet items; please see Wallet Service > Search for more information.