Templates

Define the structure, properties, and behavior of tokenized objects.

What are Templates?

Templates are the blueprint for objects. They define the schema, what properties an object has, what its default values are, and what faces (visual representations) are available. If you're familiar with object-oriented programming, templates are classes and objects are instances.

Every object on the Dual network is minted from a template. The template determines the object's structure, but each object carries its own state, property values, ownership, and activity history.

Creating a Template

Code
POST /templates
{
"name": "io.acme.product.v1",
"description": "A product authenticity token",
"private": {
"serial_number": "",
"manufacture_date": "",
"warranty_expiry": ""
}
}

The private field defines the object schema, these are the fields every object minted from this template will carry. Values you set here become defaults; they can be overridden when the object is emitted.

Naming Convention

Templates use reverse-domain notation: io.acme.product.v1. This ensures global uniqueness across organizations and makes it easy to version your templates. The convention is:

Code
{reverse-domain}.{category}.{name}.{version}

Examples: io.acme.ticket.general-admission.v2, com.example.loyalty.gold-tier.v1

Template Properties

Template properties support several field types and access levels:

  • Private fields, Only visible to the object owner and organization admins. Use for sensitive data like serial numbers, activation codes, or personal information.
  • Public fields, Visible to anyone who queries the object. Use for display data like names, descriptions, or metadata.
  • Computed fields, Derived from other properties or updated by actions. The Event Bus can modify these during action execution.

All properties are stored as JSON. There are no strict type constraints at the template level, the schema is flexible by design.

Template Variations

Variations let you create different configurations of a template without duplicating the base structure. A template for "Concert Ticket" might have variations for "VIP", "General Admission", and "Backstage Pass", each with different default property values and face configurations.

Code
POST /templates/{templateId}/variations
{
"name": "VIP",
"properties": {
"tier": "vip",
"perks": ["lounge-access", "meet-greet"],
"max_supply": 100
}
}

When emitting an object, you can specify a variation to inherit its property overrides.

Template Lifecycle

Templates go through a straightforward lifecycle:

  • Draft, Create and iterate on the template structure. Attach faces and register action types.
  • Published, Once you're satisfied, templates can be used to emit objects. Changes to a published template don't retroactively affect existing objects.
  • Versioned, When you need breaking changes, create a new version (e.g. v2) rather than modifying the existing template. This preserves the integrity of objects already in circulation.

Relationship to Other Concepts

  • Organizations, Templates are scoped to an organization. They cannot be shared across organizations.
  • Objects, Every object references a template_id. The template defines what the object can be; the object defines what it is.
  • Faces, Faces are registered against a template. All objects of that template share the same face definitions.
  • Actions, Action types are registered against templates to define what operations are valid for objects of that type.
  • Storage, Template assets (images, models, documents) are uploaded via POST /storage/template/{templateId} and associated with the template.

Best Practices

  • Version from day one, Always include a version suffix (.v1) in your template name. It costs nothing upfront and saves painful migrations later.
  • Use variations for product tiers, Rather than creating separate templates for Gold/Silver/Bronze, use a single template with variations. This keeps your face and action type registrations DRY.
  • Keep private fields minimal, Only put truly sensitive data in private fields. Public fields are cheaper to query and easier to index.