Create Your First Template
Learn how to define a template with properties, actions, and faces.
Prerequisites
- A DUAL account with an organization
- An API key or JWT token
What You'll Build
In this tutorial you'll create a template — the blueprint that defines the structure, properties, and behaviour of tokenized objects on the DUAL network. By the end you'll have a working template you can mint objects from.
Step 1 — Authenticate
DUAL uses a three-step OTP authentication flow. First, request a one-time password sent to your email:
# Step 1a — Request OTP
curl -X POST https://gateway-48587430648.europe-west6.run.app/auth/otp \
-H "Content-Type: application/json" \
-d '{ "email": "dev@example.com" }'Check your inbox for the 6-digit OTP code, then log in:
# Step 1b — Login with OTP (returns a system-scoped JWT)
curl -X POST https://gateway-48587430648.europe-west6.run.app/auth/login \
-H "Content-Type: application/json" \
-d '{
"email": "dev@example.com",
"otp": "123456"
}'The response includes an access_token (system-scoped). To perform actions within an organization, switch to an org context:
# Step 1c — Switch to organization context (returns org-scoped JWT)
curl -X POST https://gateway-48587430648.europe-west6.run.app/organizations/switch \
-H "Authorization: Bearer $SYSTEM_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "id": "your-org-id" }'Save the org-scoped access_token as an environment variable — you'll use it in every subsequent request:
export DUAL_TOKEN="eyJhbGciOiJIUzI1NiIs..."Step 2 — Create the Template
Templates define the schema for your tokenized objects. Each template belongs to an organization and specifies properties, actions, and visual faces.
curl -X POST https://gateway-48587430648.europe-west6.run.app/templates \
-H "Authorization: Bearer $DUAL_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"template": {
"name": "my-org::loyalty-card::v1",
"description": "A digital loyalty card template",
"public": false,
"cloneable": false,
"properties": {
"points": 0,
"tier": "silver",
"holder_name": ""
}
}
}'The template name follows the convention org::name::version. Properties define the default data fields that every object minted from this template will inherit.
Step 3 — Verify Your Template
Confirm the template was created by listing your organization's templates:
curl https://gateway-48587430648.europe-west6.run.app/templates \
-H "Authorization: Bearer $DUAL_TOKEN"You should see your new template in the response array with all the properties you defined.
Step 4 — Add a Face
Faces are the visual layer of your template. They can be images, 3D models, or web views. Let's attach a simple image face:
curl -X POST https://gateway-48587430648.europe-west6.run.app/faces \
-H "Authorization: Bearer $DUAL_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"face": {
"template": "my-org::loyalty-card::v1",
"display_type": "ResourceFace",
"meta": {
"image": "https://your-cdn.com/loyalty-card.png"
},
"is_default": true
}
}'What's Next?
Your template is ready. In the next tutorial, Mint & Transfer Objects, you'll create object instances from this template and transfer them between wallets.
PATCH /templates/{id}, but be aware that changes won't retroactively update objects already minted from it.