Back to recipes
Intermediate · 15 min

NFT Rewards

Create and manage on-chain NFT rewards to incentivize customers with points, discounts, free products, event passes, and exclusive access.

Prerequisites

  • Podium SDK installed and configured
  • A merchant profile (see Merchant Setup recipe)
  • Understanding of NFT basics

NFT Rewards let merchants incentivize customers with on-chain rewards. Rewards can be points, discounts, free products, event passes, or exclusive access. Each reward is minted as an NFT to the user's wallet, providing verifiable ownership and enabling cross-platform reward portability. This guide covers the full reward lifecycle: creation, configuration, publishing, distribution, and management.

1

Create an NFT reward

Start by creating a reward with a specific type. Available types are POINTS, FREE_PRODUCT, DISCOUNT_CODE, EVENT_PASS, CUSTOM_REWARD, and EXCLUSIVE_ACCESS:

rewards.ts
// Create an NFT reward for the merchant
const reward = await client.nftRewards.createNftReward({
  requestBody: {
    type: 'POINTS', // POINTS, FREE_PRODUCT, DISCOUNT_CODE, EVENT_PASS, CUSTOM_REWARD, EXCLUSIVE_ACCESS
    creatorId: 'creator_xyz', // The merchant's ID
  },
})

console.log(reward)
// {
//   id: 'reward_abc123',
//   type: 'POINTS',
//   status: 'DRAFT',
//   creatorId: 'creator_xyz',
//   createdAt: '2025-01-15T...',
// }
2

Configure reward metadata

Update the reward with NFT metadata including name, description, and image. The metadata will be stored on-chain when the NFT is minted:

rewards.ts
// Update NFT details
const updatedReward = await client.nftRewards.replace({
  id: reward.id,
  requestBody: {
    name: 'Loyalty Points NFT',
    description: '100 points redeemable at Awesome Store',
    // Image URL typically points to IPFS for on-chain permanence
    imageUrl: 'ipfs://QmXxx.../reward-badge.png',
    points: 100, // For POINTS type rewards
  },
})

console.log(updatedReward)
// {
//   id: 'reward_abc123',
//   type: 'POINTS',
//   status: 'DRAFT',
//   name: 'Loyalty Points NFT',
//   description: '100 points redeemable at Awesome Store',
//   imageUrl: 'ipfs://QmXxx.../reward-badge.png',
//   points: 100,
// }
3

Publish the reward

Once configured, publish the reward to make it available for distribution. Published rewards can be granted to users:

rewards.ts
// Publish the reward (makes it available for distribution)
const publishedReward = await client.nftRewards.publish({
  id: reward.id,
})

console.log(publishedReward)
// {
//   id: 'reward_abc123',
//   status: 'PUBLISHED',
//   name: 'Loyalty Points NFT',
//   ...
// }
4

Grant a reward to a user

Mint the NFT reward to a user. The reward is minted on-chain to their wallet address:

rewards.ts
// Grant the reward to a user
const grant = await client.nftRewards.createNftRewardGrant({
  id: reward.id,
  requestBody: {
    userId: 'user_xyz',     // The user receiving the reward
    creatorId: 'creator_xyz', // The merchant granting it
  },
})

console.log(grant)
// {
//   success: true,
//   txHash: '0x...',
//   tokenId: 1,
// }
5

List merchant rewards

Get all rewards created by a merchant to display in a dashboard or management UI:

rewards.ts
// List all rewards for a merchant
const rewards = await client.merchantNftRewards.listNftRewards({
  creatorId: 'creator_xyz',
})

console.log(rewards)
// {
//   data: [
//     {
//       id: 'reward_abc123',
//       type: 'POINTS',
//       status: 'PUBLISHED',
//       name: 'Loyalty Points NFT',
//       grantCount: 42,
//     },
//     {
//       id: 'reward_def456',
//       type: 'DISCOUNT_CODE',
//       status: 'DRAFT',
//       name: '20% Off Next Purchase',
//       grantCount: 0,
//     },
//   ],
//   total: 2,
// }
6

Disable a reward

Disable a reward to prevent new grants. Existing grants remain valid:

rewards.ts
// Disable a reward (no new grants allowed)
const disabledReward = await client.nftRewards.disable({
  id: 'reward_abc123',
})

console.log(disabledReward)
// {
//   id: 'reward_abc123',
//   status: 'DISABLED',
//   name: 'Loyalty Points NFT',
//   grantCount: 42, // Existing grants still valid
// }

Complete Example

Here's a complete working example combining all the steps:

complete-example.ts
import { createPodiumClient } from '@podiumcommerce/node-sdk'

const client = createPodiumClient({
  apiKey: process.env.PODIUM_API_KEY,
})

// Create and configure a new reward
async function createLoyaltyReward(
  creatorId: string,
  name: string,
  points: number,
  imageUrl: string // Typically an IPFS URL for on-chain permanence
) {
  // Step 1: Create the reward
  const reward = await client.nftRewards.createNftReward({
    requestBody: {
      type: 'POINTS',
      creatorId,
    },
  })

  // Step 2: Configure metadata
  await client.nftRewards.replace({
    id: reward.id,
    requestBody: {
      name,
      description: `${points} loyalty points`,
      imageUrl, // e.g., 'ipfs://QmXxx.../image.png'
      points,
    },
  })

  // Step 3: Publish
  const published = await client.nftRewards.publish({ id: reward.id })
  console.log('Created reward:', published.id)

  return published
}

// Grant rewards to multiple users (e.g., after a purchase)
async function grantRewardsToUsers(
  rewardId: string,
  creatorId: string,
  userIds: string[]
) {
  const results = await Promise.all(
    userIds.map(userId =>
      client.nftRewards.createNftRewardGrant({
        id: rewardId,
        requestBody: { userId, creatorId },
      })
    )
  )

  console.log(`Granted reward to ${results.length} users`)
  return results
}

// Get reward analytics for a merchant
async function getRewardAnalytics(creatorId: string) {
  const rewards = await client.merchantNftRewards.listNftRewards({ creatorId })

  return {
    totalRewards: rewards.total,
    publishedRewards: rewards.data.filter(r => r.status === 'PUBLISHED').length,
    totalGrants: rewards.data.reduce((sum, r) => sum + r.grantCount, 0),
    byType: rewards.data.reduce((acc, r) => {
      acc[r.type] = (acc[r.type] || 0) + 1
      return acc
    }, {} as Record<string, number>),
  }
}

// Usage
const reward = await createLoyaltyReward(
  'creator_xyz',
  'Welcome Bonus',
  100,
  'ipfs://QmXxx.../welcome-badge.png'
)

// Grant to new customers
await grantRewardsToUsers(reward.id, 'creator_xyz', [
  'user_123',
  'user_456',
  'user_789',
])

// Check analytics
const analytics = await getRewardAnalytics('creator_xyz')
console.log('Reward analytics:', analytics)

Explore the full API

See all available endpoints and parameters in the API reference.

API Docs