Code Samples

Copy-paste examples for common Dual workflows in TypeScript, Python, and cURL.

Authenticate & Get Current Wallet

TypeScript SDK

Code
import { DualClient } from "dual-sdk";
// Using API Key
const client = new DualClient({
token: process.env.DUAL_API_KEY,
authMode: 'api_key'
});
// Using Bearer JWT Token
const clientBearer = new DualClient({
token: process.env.DUAL_JWT_TOKEN,
authMode: 'bearer'
});
const wallet = await client.wallets.me();
console.log(wallet.address);

Python SDK

Code
from dual_sdk import DualClient
# Using API Key
client = DualClient(
token=os.environ["DUAL_API_KEY"],
auth_mode="api_key"
)
# Using Bearer JWT Token
client_bearer = DualClient(
token=os.environ["DUAL_JWT_TOKEN"],
auth_mode="bearer"
)
wallet = client.wallets.me()
print(wallet.address)

cURL with API Key

Code
curl -H "x-api-key: $DUAL_API_KEY" \\
https://api-testnet.dual.network/wallets/me

cURL with Bearer Token

Code
curl -H "Authorization: Bearer $DUAL_JWT_TOKEN" \\
https://api-testnet.dual.network/wallets/me

Create a Template & Mint an Object

TypeScript SDK

Code
// 1. Create template
const template = await client.templates.create({
name: "Concert Ticket",
description: "Tokenized concert ticket",
properties: {
event_name: "string",
tier: "string",
redeemed: "boolean",
},
});
// 2. Mint object using ebus action
const action = await client.eventBus.execute({
actionType: "emit",
templateId: template.id,
properties: {
event_name: "Summer Festival 2026",
tier: "general",
redeemed: false,
seat: "GA-042",
},
});
const ticket = await client.objects.get(action.objectId);

Python SDK

Code
from dual_sdk import DualClient
client = DualClient(
token=os.environ["DUAL_API_KEY"],
auth_mode="api_key"
)
# 1. Create template
template = client.templates.create({
"name": "Concert Ticket",
"description": "Tokenized concert ticket",
"properties": {
"event_name": "string",
"tier": "string",
"redeemed": "boolean",
},
})
# 2. Mint object using ebus action
action = client.event_bus.execute({
"action_type": "emit",
"template_id": template["id"],
"properties": {
"event_name": "Summer Festival 2026",
"tier": "general",
"redeemed": False,
"seat": "GA-042",
},
})
ticket = client.objects.get(action["object_id"])

Transfer an Object

Code
// TypeScript
await client.eventBus.execute({
actionType: "transfer",
objectId: ticket.id,
payload: { to: "0xRecipientAddress" },
});
// Python
client.event_bus.execute({
"action_type": "transfer",
"object_id": ticket.id,
"payload": {"to": "0xRecipientAddress"},
})

Search Objects by Property

Code
// TypeScript
const vipTickets = await client.objects.search({
templateId: template.id,
properties: { tier: "vip" },
limit: 50,
});
# Python
from dual_sdk import ObjectQuery
vip_tickets = client.objects.search(ObjectQuery(
template_id=template.id,
properties={"tier": "vip"},
limit=50,
))

Listen for Webhooks

Always verify webhook signatures using HMAC-SHA256 before processing events:

Code
import * as crypto from "crypto";
import express from "express";
const webhookSecret = process.env.DUAL_WEBHOOK_SECRET;
const app = express();
app.use(express.json());
// Express.js webhook handler with signature verification
app.post("/webhooks/dual", (req, res) => {
// 1. Verify signature
const signature = req.headers["x-dual-signature"] as string;
const timestamp = req.headers["x-dual-timestamp"] as string;
const body = JSON.stringify(req.body);
const message = \`\${timestamp}.\${body}\`;
const expectedSignature = crypto
.createHmac("sha256", webhookSecret)
.update(message)
.digest("hex");
if (signature !== expectedSignature) {
console.error("Invalid webhook signature!");
return res.status(401).send("Unauthorized");
}
// 2. Process event
const { event, payload } = req.body;
switch (event) {
case "object.created":
console.log("New object:", payload.object_id);
break;
case "object.transferred":
console.log("Transfer:", payload.from, "→", payload.to);
break;
}
res.sendStatus(200);
});

Upload an Asset to Storage

Code
# Python, upload an image and attach it to a template
url = client.storage.upload("ticket_artwork.png", open("artwork.png", "rb"))
client.templates.update(template.id, {"properties": {"image_url": url}})

Further Reading