Skip to main content
These examples use the Podium TypeScript SDK. Each section is a self-contained workflow you can adapt for your application.
import { createPodiumClient, ApiError } from '@podium-sdk/node-sdk'

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

Product Catalog Management

Create, Configure, and Publish a Product

const product = await client.merchantProducts.create({
  creatorId: 'creator_abc',
  requestBody: {
    name: 'Organic Face Serum',
    slug: 'organic-face-serum',
    description: 'Lightweight hydrating serum with hyaluronic acid and vitamin C',
    price: 2500,
    maxDiscount: 500,
    allowedPointSources: null,
    media: [
      { url: 'https://cdn.example.com/serum-hero.jpg', type: 'IMAGE', order: 0 },
      { url: 'https://cdn.example.com/serum-texture.jpg', type: 'IMAGE', order: 1 },
    ],
  },
})

await client.merchantProducts.updateByProductId({
  creatorId: 'creator_abc',
  productId: product.id,
  requestBody: {
    supply: 200,
    pointEligibility: 'ELIGIBLE',
    shippingType: 'STANDARD',
    attributes: [
      {
        name: 'Size',
        type: 'VARIANT',
        variants: [
          { value: '30ml', price: 2500, supply: 100, order: 0 },
          { value: '50ml', price: 3500, supply: 60, order: 1 },
          { value: '100ml', price: 5000, supply: 40, order: 2 },
        ],
      },
    ],
  },
})

await client.merchantProducts.publish({
  creatorId: 'creator_abc',
  productId: product.id,
  requestBody: { userId: 'admin_user_id' },
})

List and Filter Products

const published = await client.product.list({
  categories: '1,2,3',
  page: 1,
  limit: 20,
})

const creatorProducts = await client.merchantProducts.list({
  creatorId: 'creator_abc',
  status: 'PUBLISHED',
})

Order and Checkout Workflows

Stripe Checkout (Consumer App)

const order = await client.userOrders.create({
  id: userId,
  requestBody: { productId: 'clx9prod001', quantity: 1 },
})

await client.userOrderProducts.createByProductId({
  id: userId,
  orderId: order.id,
  productId: 'clx9prod001',
  requestBody: { quantity: 1, variantIds: ['clx9var_30ml'] },
})

const shippingQuote = await client.order.createShippingQuote({
  id: order.id,
  requestBody: {
    firstName: 'Jane',
    lastName: 'Doe',
    address: {
      line1: '123 Main St',
      line2: null,
      city: 'San Francisco',
      state: 'CA',
      postalCode: '94102',
      countryCode: 'US',
    },
  },
})

const checkout = await client.userOrder.checkout({
  id: userId,
  orderId: order.id,
  requestBody: { points: 500 },
})
// checkout contains Stripe PaymentIntent clientSecret

// After Stripe webhook confirms payment:
await client.userOrderPoints.replaceFinalize({
  id: userId,
  orderId: order.id,
})

x402 Checkout (Agent)

The x402 payment flow uses HTTP directly — it negotiates USDC payment via response headers:
const response = await fetch(
  `https://api.podium.build/api/v1/x402/order/${orderId}/pay`,
  { method: 'POST' }
)

if (response.status === 402) {
  const requirements = response.headers.get('X-PAYMENT-REQUIREMENTS')
  const parsed = JSON.parse(atob(requirements!))

  const paymentPayload = await signUsdcTransfer({
    to: parsed.payTo,
    amount: parsed.maxAmountRequired,
    network: 'base',
  })

  const receipt = await fetch(
    `https://api.podium.build/api/v1/x402/order/${orderId}/pay`,
    {
      method: 'POST',
      headers: { 'X-PAYMENT': btoa(JSON.stringify(paymentPayload)) },
    }
  )
}
Or use the SDK for the final settlement after signing the payment:
await client.x402.createOrderPay({ id: orderId })

Buy Now (Single-Step Purchase)

const result = await client.product.buyNow({
  id: 'clx9prod001',
  requestBody: {
    quantity: 1,
    variantIds: ['clx9var_30ml'],
    shouldUseStripe: true,
  },
})

Guest Checkout

const guestOrder = await client.guests.createOrder({
  requestBody: { productId: 'clx9prod001', quantity: 1 },
})

await client.guests.createOrderProductByProductId({
  id: guestOrder.id,
  productId: 'clx9prod001',
  requestBody: { quantity: 1 },
})

const checkout = await client.guests.checkout({ id: guestOrder.id })

Campaign Workflows

Create and Run a Swipe Campaign

const campaign = await client.campaigns.create({
  requestBody: {
    creatorId: 'creator_abc',
    type: 'SWIPE',
  },
})

await client.campaigns.replace({
  id: campaign.id,
  requestBody: {
    title: 'What moisturizer matches your skin?',
    description: 'Swipe right on your favorites',
    startDate: new Date().toISOString(),
    endDate: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString(),
  },
})

await client.campaigns.updateSubmit({ id: campaign.id })
await client.campaigns.publish({
  id: campaign.id,
  requestBody: { requiresReview: false },
})

await client.campaigns.vote({
  id: campaign.id,
  requestBody: {
    userId: 'user_123',
    votes: [{ attributeId: 1, optionId: 2 }],
  },
})

const analytics = await client.campaigns.getAnalytics({ id: campaign.id })

Run a Survey Campaign

const survey = await client.campaigns.create({
  requestBody: {
    creatorId: 'creator_abc',
    type: 'SURVEY',
  },
})

await client.campaigns.createSurvey({
  id: survey.id,
  requestBody: {
    userId: 'user_456',
    responses: [
      { questionId: 1, answer: 'Oily skin' },
      { questionId: 2, answer: ['Hydration', 'SPF'] },
    ],
  },
})

const report = await client.campaigns.getSurveyReport({ id: survey.id })

Companion Agent Workflows

Full Agent Lifecycle

const user = await client.user.create({
  requestBody: {
    email: 'shopper@example.com',
    privyId: 'did:privy:abc123',
  },
})

const { data: profile } = await client.companion.createProfile({
  userId: user.id,
  requestBody: {
    skinType: 'Oily',
    concerns: ['Acne', 'SPF protection'],
    priceRange: { min: 15, max: 50 },
    brands: ['CeraVe', 'The Ordinary'],
    avoidances: ['fragrance', 'alcohol'],
  },
})

const { data: recs } = await client.companion.listRecommendations({
  userId: user.id,
})

await client.companion.createInteractions({
  requestBody: {
    userId: user.id,
    productId: recs[0].id,
    action: 'RANK_UP',
  },
})

const { data: order } = await client.companion.createOrders({
  requestBody: {
    userId: user.id,
    productId: recs[0].id,
    shippingAddress: { street: '123 Main St', city: 'San Francisco', state: 'CA', zip: '94102' },
    email: 'shopper@example.com',
  },
})

await client.companion.createProfilePoints({
  userId: user.id,
  requestBody: {
    amount: 25,
    details: { reason: 'order_placed', orderId: order.id },
  },
})

Points and Loyalty

Earn and Spend Points

await client.user.createPoints({
  id: userId,
  requestBody: {
    amount: 50,
    creatorId: 'creator_abc',
    details: { source: 'campaign_completion', campaignId: 'campaign_abc' },
  },
})

const balance = await client.user.getPoints({ id: userId })

const history = await client.user.getPointsHistory({
  id: userId,
  page: 1,
  limit: 20,
  order: 'desc',
})

// Apply points to an order, then finalize after payment
await client.userOrder.checkout({
  id: userId,
  orderId: orderId,
  requestBody: { points: 200 },
})

// After payment succeeds:
await client.userOrderPoints.replaceFinalize({ id: userId, orderId })

// If payment fails, revert the points hold:
await client.userOrderPoints.revert({ id: userId, orderId })

Task Pool (On-Chain Bounties)

Create a Task

const { data: task } = await client.tasks.createTask({
  requestBody: {
    merchantAddress: '0x742d35Cc6634C0532925a3b844Bc9e7595f2bD18',
    amountUSDC: 5.0,
    acceptanceCriteria: 'Write a 200+ word product review with personal experience, star rating 1-5, and photo',
    verificationMethod: 'Oracle',
    durationSeconds: 86400,
    campaignId: 'campaign_abc',
  },
})

Solver Workflow (HTTP)

const BASE = 'https://api.podium.build/api/v1'
const headers = {
  'Authorization': `Bearer ${process.env.PODIUM_API_KEY}`,
  'Content-Type': 'application/json',
}

const solver = await fetch(`${BASE}/solver/register`, {
  method: 'POST',
  headers,
  body: JSON.stringify({ walletAddress: '0xSolverAddress...' }),
}).then(r => r.json())

const tasks = await fetch(`${BASE}/solver/tasks`, { headers }).then(r => r.json())

await fetch(`${BASE}/solver/tasks/${taskId}/claim`, {
  method: 'POST',
  headers,
})

await fetch(`${BASE}/solver/tasks/${taskId}/submit`, {
  method: 'POST',
  headers,
  body: JSON.stringify({
    proof: 'https://example.com/review-link',
    metadata: { wordCount: 342, rating: 4 },
  }),
})

On-Chain Rewards

Create and Manage Reward Programs

const reward = await client.nftRewards.createNftReward({
  requestBody: {
    type: 'FREE_PRODUCT',
    creatorId: 'creator_abc',
  },
})

await client.nftRewards.replace({
  id: reward.id,
  requestBody: {
    name: 'Free Serum Reward',
    description: 'Redeem for a free Organic Face Serum',
    imageUrl: 'https://cdn.example.com/reward.png',
    points: 500,
  },
})

await client.nftRewards.publish({ id: reward.id })

// Grant a reward to a user
await client.nftRewards.createNftRewardGrant({
  id: reward.id,
  requestBody: {
    userId: 'user_123',
    creatorId: 'creator_abc',
  },
})

Check and Redeem User Rewards

const earned = await client.userNfTs.listEarned({ id: userId })
const redeemable = await client.userNfTs.listRedeemable({ id: userId })

await client.userNfTs.redeem({
  id: userId,
  network: 'base',
  address: '0xNftContract...',
  tokenId: '42',
})

const status = await client.userNfTs.getStatus({
  id: userId,
  network: 'base',
  address: '0xNftContract...',
  tokenId: '42',
})

Reward Types

TypeDescription
FREE_PRODUCTRedeem for a free product
DISCOUNT_CODEPercentage or fixed discount
EVENT_PASSAccess pass for events
POINTSBonus point grant
EXCLUSIVE_ACCESSGated content or early access
CUSTOM_REWARDCustom reward type

Agentic Commerce (Public Endpoints)

Query the Agentic Product Feed

No API key required — designed for machine consumption:
const feed = await client.agentic.listProductsFeed({
  page: 1,
  limit: 20,
  categories: '1,2,3',
})
Or via HTTP with intent context headers:
const response = await fetch(
  'https://api.podium.build/api/v1/agentic/products/feed?page=1&limit=20',
  {
    headers: {
      'X-INTENT-CONTEXT': JSON.stringify({
        concerns: ['hydration'],
        priceRange: { min: 10, max: 50 },
      }),
    },
  }
)
const products = await response.json()

Create an Agentic Checkout Session

const session = await client.agentic.createCheckoutSessions({
  requestBody: {
    items: [{ id: 'clx9prod001', quantity: 1 }],
    shippingAddress: {
      firstName: 'Jane',
      lastName: 'Doe',
      address: {
        line1: '123 Main St',
        line2: null,
        city: 'San Francisco',
        state: 'CA',
        postalCode: '94102',
        countryCode: 'US',
      },
    },
  },
})

// Update the session with email
const updated = await client.agentic.updateCheckoutSessions({
  id: session.id,
  requestBody: { email: 'customer@example.com' },
})

// Check session state
const state = await client.agentic.getCheckoutSessions({ id: session.id })

Shopify Integration

List and Sync Shopify Products

const available = await client.shopify.getProductsAvailableByCreatorId({
  creatorId: 'creator_abc',
})

await client.shopify.sync({
  creatorId: 'creator_abc',
  requestBody: { productIds: ['shopify_prod_1', 'shopify_prod_2'] },
})

const shop = await client.shopify.getShopByCreatorId({
  creatorId: 'creator_abc',
})

Error Handling

All SDK methods throw ApiError with structured error details:
import { createPodiumClient, ApiError } from '@podium-sdk/node-sdk'

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

try {
  const products = await client.product.list({ page: 1 })
} catch (error) {
  if (error instanceof ApiError) {
    console.error(`${error.status} ${error.statusText}: ${error.message}`)
    console.error('URL:', error.url)
    console.error('Body:', error.body)
  }
}
Common error codes:
StatusMeaning
400Validation error (check request body)
401Missing or invalid API key
403Insufficient permissions for this resource
404Resource not found
409Conflict (e.g., duplicate slug)
429Rate limit exceeded