Code Samples

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

Authenticate & Get Current Wallet

TypeScript SDK

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

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

curl -H "x-api-key: $DUAL_API_KEY" \
     https://gateway-48587430648.europe-west6.run.app/wallets/me

cURL with Bearer Token

curl -H "Authorization: Bearer $DUAL_JWT_TOKEN" \
     https://gateway-48587430648.europe-west6.run.app/wallets/me

Create a Template & Mint an Object

TypeScript SDK

// 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

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

// 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

// 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:

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

# 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