Skip to main content
This guide walks you through the complete tokenization workflow using the Oumla SDK, from creating collections to minting and burning tokens.
Two Ways to Use Oumla: This guide uses the TypeScript SDK. You can also accomplish the same tasks using direct REST API calls - see the API Reference for endpoint details.

Overview

The tokenization workflow involves several steps:
  1. Create Collection - Deploy an NFT collection contract (ERC-721 or ERC-1155)
  2. Check Status - Monitor the async deployment workflow
  3. Mint Tokens - Mint NFTs to specific addresses
  4. View Tokens - Query tokens in your collection
  5. Burn Tokens - Remove tokens from circulation (optional)
Collection creation and minting use Temporal workflows for async processing. You’ll need to check workflow status to know when operations complete.

Prerequisites

Before starting, ensure you have:
  • An initialized SDK client
  • A profile created
  • An address generated (for contract deployment)
  • Your client share (for signing operations)

Step 1: Create a Collection

Creating a collection deploys a new NFT contract. This is an async operation that returns a workflow ID.
import { OumlaSdkApiClient, OumlaSdkApiEnvironment } from '@oumla/sdk';

const client = new OumlaSdkApiClient({
  environment: OumlaSdkApiEnvironment.Sandbox,
  apiKey: 'your-api-key-here'
});

// Create an ERC-721 collection (NON_FUNGIBLE_TOKEN)
const collection = await client.tokenization.createCollection({
  addressId: 'your-address-id',
  type: 'NON_FUNGIBLE_TOKEN',
  clientShare: 'your-client-share',
  network: 'ETHEREUM',
  displayName: 'My NFT Collection',
  useGasless: false,
  fee: '0',
  feeLevel: 'standard',
  description: 'Optional collection description',
  createParams: {
    initializeParams: [
      { name: '_name', type: 'string', value: 'My Collection' },
      { name: '_symbol', type: 'string', value: 'MYC' },
      { name: 'defaultAdmin', type: 'address', value: '0x1111111111111111111111111111111111111111' },
      { name: 'minter', type: 'address', value: '0x2222222222222222222222222222222222222222' },
      { name: 'pauser', type: 'address', value: '0x3333333333333333333333333333333333333333' }
    ]
  }
});

console.log('Workflow ID:', collection.data.workflowId);
// Create an ERC-1155 collection (SEMI_FUNGIBLE_TOKEN)
const collection = await client.tokenization.createCollection({
  addressId: 'your-address-id',
  type: 'SEMI_FUNGIBLE_TOKEN',
  clientShare: 'your-client-share',
  network: 'ETHEREUM',
  displayName: 'My Multi-Token Collection',
  createParams: {
    initializeParams: [
      { name: '_name', type: 'string', value: 'My Multi-Token Collection' },
      { name: '_symbol', type: 'string', value: 'MMTC' },
      { name: 'defaultAdmin', type: 'address', value: '0x1111111111111111111111111111111111111111' },
      { name: 'minter', type: 'address', value: '0x2222222222222222222222222222222222222222' },
      { name: 'pauser', type: 'address', value: '0x3333333333333333333333333333333333333333' }
    ]
  }
});

Collection Types

  • NON_FUNGIBLE_TOKEN (ERC-721): Non-fungible tokens (NFTs) - each token is unique
  • SEMI_FUNGIBLE_TOKEN (ERC-1155): Multi-token standard - supports both fungible and non-fungible tokens
Use NON_FUNGIBLE_TOKEN for ERC-721 collections and SEMI_FUNGIBLE_TOKEN for ERC-1155 collections. These are the actual API values, not ERC721 or ERC1155.

Step 2: Check Workflow Status

Collection creation is async. Check the workflow status to know when deployment completes:
// Check workflow status
const status = await client.temporal.getWorkflowStatus({
  workflowId: collection.data.workflowId
});

console.log('Status:', status.data.status); // COMPLETED, RUNNING, FAILED
console.log('Result:', status.data.result);

if (status.data.status === 'COMPLETED') {
  console.log('Collection deployed at:', status.data.result.contractAddress);
} else if (status.data.status === 'FAILED') {
  console.error('Deployment failed:', status.data.error);
}

Workflow Status Values

  • RUNNING: Operation in progress
  • COMPLETED: Operation successful
  • FAILED: Operation failed (check error details)
  • CANCELLED: Operation was cancelled
Poll the workflow status endpoint every few seconds until status is COMPLETED or FAILED. Consider implementing exponential backoff for production applications.

Step 3: Get Collection Details

Once deployment completes, retrieve collection details:
const collectionDetails = await client.tokenization.getCollectionById(
  collection.collectionId
);

console.log('Collection:', collectionDetails.data);
console.log('Contract Address:', collectionDetails.data.contractAddress);
console.log('Network:', collectionDetails.data.network);

Step 4: Mint Tokens

Mint tokens to specific addresses. For ERC-721, mint unique tokens. For ERC-1155, specify token ID and amount.

Minting ERC-721 Tokens

const mintResult = await client.tokenization.mintToken({
  id: collection.collectionId,
  addressId: 'your-address-id',
  clientShare: 'your-client-share',
  to: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb', // Recipient address
  tokenId: '0', // Sequential token ID (start from 0)
  metadata: {
    name: 'My First NFT',
    description: 'This is my first NFT',
    image: 'https://example.com/image.png',
    attributes: [
      {
        trait_type: 'Color',
        value: 'Blue'
      }
    ]
  }
});

console.log('Mint Workflow ID:', mintResult.mint.workflowId);

Minting ERC-1155 Tokens

const mintResult = await client.tokenization.mintToken({
  id: collection.collectionId,
  addressId: 'your-address-id',
  clientShare: 'your-client-share',
  to: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb',
  tokenId: '1', // Token type ID
  amount: '100', // Amount to mint (for ERC-1155)
  metadataURI: 'https://api.example.com/metadata/1'
});

console.log('Mint Workflow ID:', mintResult.mint.workflowId);
Token ID Sequencing: For ERC-721 collections, token IDs must be sequential starting from 0. The system validates this to prevent conflicts.

Step 5: Check Mint Status

Minting is also async. Check the workflow status:
const mintStatus = await client.temporal.getWorkflowStatus({
  workflowId: mintResult.data.mint?.workflowId
});

if (mintStatus.data.status === 'COMPLETED') {
  console.log('Token minted successfully!');
  console.log('Transaction Hash:', mintStatus.data.result.transactionHash);
}

Step 6: View Collection Tokens

List all tokens in your collection:
const tokens = await client.tokenization.getCollectionTokens({
  id: collection.collectionId,
  skip: 0,
  take: 25
});

console.log('Total tokens:', tokens.data.tokens.length);
tokens.data.tokens.forEach(token => {
  console.log(`Token ${token.tokenId}:`, token);
});

Step 7: Get Token Details

Get details for a specific token:
const tokenDetails = await client.tokenization.getCollectionTokenDetails({
  id: collection.collectionId,
  tokenId: '0'
});

console.log('Token Details:', tokenDetails.data);
console.log('Owner:', tokenDetails.data.owner);
console.log('Metadata:', tokenDetails.data.metadata);

Step 8: Burn Tokens (Optional)

Burn tokens to remove them from circulation:
const burnResult = await client.tokenization.burnToken('collection-id', {
  addressId: 'your-address-id',
  clientShare: 'your-client-share',
  tokenId: '0' // Token ID to burn
});

console.log('Burn Workflow ID:', burnResult.data.burn?.workflowId);

// Check burn status
const burnStatus = await client.temporal.getWorkflowStatus({
  workflowId: burnResult.data.burn?.workflowId
});

Complete Example

Here’s a complete example that ties everything together:
import { OumlaSdkApiClient, OumlaSdkApiEnvironment } from '@oumla/sdk';

const client = new OumlaSdkApiClient({
  environment: OumlaSdkApiEnvironment.Sandbox,
  apiKey: process.env.OUMLA_API_KEY
});

async function tokenizationWorkflow() {
  try {
    // Step 1: Create collection
    const collection = await client.tokenization.createCollection({
      addressId: process.env.ADDRESS_ID,
      type: 'NON_FUNGIBLE_TOKEN', // Use 'NON_FUNGIBLE_TOKEN' for ERC-721, 'SEMI_FUNGIBLE_TOKEN' for ERC-1155
      clientShare: process.env.CLIENT_SHARE,
      network: 'ETHEREUM',
      displayName: 'My NFT Collection',
      createParams: {
        initializeParams: [
          { name: '_name', type: 'string', value: 'My Collection' },
          { name: '_symbol', type: 'string', value: 'MYC' },
          { name: 'defaultAdmin', type: 'address', value: process.env.ADMIN_ADDRESS },
          { name: 'minter', type: 'address', value: process.env.MINTER_ADDRESS },
          { name: 'pauser', type: 'address', value: process.env.PAUSER_ADDRESS }
        ]
      }
    });

    console.log('Collection creation started. Workflow ID:', collection.data.workflowId);

    // Step 2: Wait for collection deployment
    let collectionStatus;
    do {
      await new Promise(resolve => setTimeout(resolve, 3000)); // Wait 3 seconds
      collectionStatus = await client.temporal.getWorkflowStatus({
        workflowId: collection.data.workflowId
      });
      console.log('Collection status:', collectionStatus.data.status);
    } while (collectionStatus.data.status === 'RUNNING');

    if (collectionStatus.data.status === 'FAILED') {
      throw new Error('Collection deployment failed: ' + collectionStatus.data.error);
    }

    const contractAddress = collectionStatus.data.result.contractAddress;
    console.log('Collection deployed at:', contractAddress);

    // Step 3: Get collection ID from workflow result (implementation-specific)
    const collectionId = 'collection-id'; // Retrieved from workflow result
    
    // Step 4: Mint a token
    const mintResult = await client.tokenization.mintToken(collectionId, {
      addressId: process.env.ADDRESS_ID,
      clientShare: process.env.CLIENT_SHARE,
      to: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb',
      metadata: {
        name: 'My First NFT',
        description: 'This is my first NFT',
        image: 'https://example.com/image.png'
      }
    });

    console.log('Minting started. Workflow ID:', mintResult.data.mint?.workflowId);

    // Step 5: Wait for mint to complete
    let mintStatus;
    do {
      await new Promise(resolve => setTimeout(resolve, 3000));
      mintStatus = await client.temporal.getWorkflowStatus({
        workflowId: mintResult.data.mint?.workflowId
      });
      console.log('Mint status:', mintStatus.data.status);
    } while (mintStatus.data.status === 'RUNNING');

    if (mintStatus.data.status === 'COMPLETED') {
      console.log('Token minted successfully!');
      console.log('Transaction Hash:', mintStatus.data.result.transactionHash);
    }

    // Step 6: View tokens
    const tokens = await client.tokenization.getCollectionTokens({
      id: collectionId,
      skip: 0,
      take: 10
    });

    console.log('Collection tokens:', tokens.data.tokens);

  } catch (error) {
    console.error('Error:', error);
  }
}

tokenizationWorkflow();

Workflow Status Values

When checking workflow status, you’ll receive one of these values:
  • RUNNING: Operation is in progress
  • COMPLETED: Operation completed successfully
  • FAILED: Operation failed (check error field for details)
  • CANCELLED: Operation was cancelled

Common Issues

Collection Deployment Fails

Causes:
  • Insufficient gas balance
  • Invalid constructor parameters
  • Network connectivity issues
Solutions:
  • Ensure address has sufficient ETH for gas
  • Verify constructor parameters match contract requirements
  • Check network status and retry

Minting Fails

Causes:
  • Invalid token ID (not sequential for ERC-721)
  • Collection not deployed yet
  • Insufficient gas balance
Solutions:
  • Ensure token IDs are sequential starting from 0
  • Wait for collection deployment to complete
  • Verify sufficient gas balance

Workflow Status Stuck

Causes:
  • Network congestion
  • Transaction pending in mempool
Solutions:
  • Wait longer (some operations take time)
  • Check blockchain explorer for transaction status
  • Contact support if stuck for extended period

Best Practices

  1. Always check workflow status before proceeding to next steps
  2. Handle errors gracefully - workflows can fail
  3. Use sequential token IDs for ERC-721 collections
  4. Store workflow IDs for tracking and debugging
  5. Implement retry logic for transient failures
  6. Monitor gas prices for cost optimization
  7. Validate addresses before minting tokens

Next Steps