Installation
npm install @podium-sdk/node-sdk
The SDK is published as @podium-sdk/node-sdk on npm with full TypeScript type definitions.
Configuration
import { createPodiumClient } from '@podium-sdk/node-sdk'
const client = createPodiumClient({
apiKey: process.env.PODIUM_API_KEY
})
The SDK auto-detects the environment from your key prefix:
| Key Prefix | Routes To |
|---|
podium_test_ | https://podium-staging.up.railway.app/api/v1 |
podium_live_ | https://api.podium.build/api/v1 |
Environment Setup
Add your API key to your .env file:
# Get your key from https://app.podium.build/onboarding
PODIUM_API_KEY=podium_test_sk_your_key_here
Never commit API keys to version control. Always load them from environment variables or a secrets manager.
Custom Base URL
Override the auto-detected base URL for local development or custom deployments:
const client = createPodiumClient({
apiKey: process.env.PODIUM_API_KEY,
baseUrl: 'http://localhost:3030/api/v1'
})
Multi-Tenant Context
Every API call is scoped to the organization that owns your API key. You don’t need to pass an organizationId — the Podium middleware extracts it from your key automatically.
If your organization manages multiple creators, all creator-scoped operations (products, orders, campaigns) are accessible through your single API key:
const creatorA = await client.merchant.getBySlug({ slug: 'brand-a' })
const creatorB = await client.merchant.getBySlug({ slug: 'brand-b' })
SDK Namespaces
The SDK is organized into namespaces that mirror the API structure:
| Namespace | Covers |
|---|
client.product | Product listing, buy-now |
client.merchantProducts | Product CRUD, variants, publish lifecycle, analytics |
client.merchant | Creator profiles, stats |
client.merchantOrders | Creator order management, shipping labels |
client.user | User creation, profile, points, orders, notifications |
client.userOrder | Checkout (Stripe, Coinbase, embedded wallet) |
client.userOrders | Order listing, creation |
client.campaigns | Campaign CRUD, voting, surveys, analytics |
client.nftRewards | Reward programs, minting, grants, publishing |
client.userNfTs | User reward redemption, earned/redeemable queries |
client.agentic | Agentic product feed, checkout sessions |
client.search | Product search with filters |
client.universalSearch | Cross-entity search with LLM-powered answers |
client.x402 | x402 USDC payment processing |
client.apiKeys | API key rotation and management |
client.organizations | Organization settings |
Basic Usage
const products = await client.product.list({ page: 1, limit: 20 })
const creator = await client.merchant.getBySlug({ slug: 'clean-beauty-co' })
const user = await client.user.create({
requestBody: {
email: 'user@example.com',
privyId: 'did:privy:abc123'
}
})
const balance = await client.user.getPoints({ id: user.id })
List endpoints return paginated results. Use page and limit parameters:
const page1 = await client.product.list({ page: 1, limit: 20 })
const page2 = await client.product.list({ page: 2, limit: 20 })
All paginated responses include a pagination object:
interface PaginatedResponse<T> {
data: T[];
pagination: {
page: number;
limit: number;
total: number;
};
}
Iterate All Pages
async function getAllProducts() {
const products = []
let page = 1
let hasMore = true
while (hasMore) {
const result = await client.product.list({ page, limit: 100 })
products.push(...result.data)
hasMore = result.data.length === 100
page++
}
return products
}
Error Handling
The SDK throws typed errors with HTTP status codes and structured error bodies:
import { ApiError } from '@podium-sdk/node-sdk'
try {
const products = await client.product.list({ page: 1 })
} catch (error) {
if (error instanceof ApiError) {
console.error(`API Error ${error.status}: ${error.message}`)
console.error('Response body:', error.body)
if (error.status === 401) console.log('Invalid API key')
if (error.status === 429) console.log('Rate limited, retry later')
if (error.status === 402) console.log('x402 payment required')
}
}
Error Codes
| Status | Meaning |
|---|
400 | Bad request — invalid parameters |
401 | Unauthorized — invalid or missing API key |
402 | Payment required — x402 payment needed |
403 | Forbidden — insufficient permissions |
404 | Not found |
409 | Conflict — duplicate resource |
422 | Validation error — request body failed Zod validation |
429 | Rate limited — check Retry-After header |
500 | Server error |
Validation Errors (422)
Podium uses Zod for request validation. Validation errors include field-level details:
{
"status": 422,
"error": "Validation Error",
"details": [
{
"path": ["email"],
"message": "Invalid email",
"code": "invalid_string"
},
{
"path": ["amount"],
"message": "Expected number, received string",
"code": "invalid_type"
}
]
}
Retry and Backoff
The SDK does not include automatic retries. Implement retry logic for transient errors:
async function withRetry<T>(
fn: () => Promise<T>,
maxRetries = 3,
baseDelayMs = 1000
): Promise<T> {
for (let attempt = 0; attempt <= maxRetries; attempt++) {
try {
return await fn();
} catch (error: any) {
const isRetryable = [429, 500, 502, 503].includes(error.status);
if (!isRetryable || attempt === maxRetries) throw error;
const delay = baseDelayMs * Math.pow(2, attempt) + Math.random() * 500;
await new Promise(r => setTimeout(r, delay));
}
}
throw new Error('Unreachable');
}
const products = await withRetry(() =>
client.product.list({ page: 1 })
)
For 429 responses, respect the Retry-After header when available.
Rate Limits
Rate limits are per-API-key and based on your subscription tier:
| Tier | Calls/Month | Burst Rate |
|---|
| Builder (Free) | 10,000 | 10 req/s |
| Growth ($99/mo) | 100,000 | 50 req/s |
| Pro ($499/mo) | 1,000,000 | 200 req/s |
| Enterprise | Custom | Custom |
Rate limit headers are included in every response:
X-RateLimit-Limit: 50
X-RateLimit-Remaining: 47
X-RateLimit-Reset: 1709827260
SDK Generation
The SDK uses a hybrid generation approach:
- OpenAPI spec generated from Zod schemas via a build script
- Service classes auto-generated via
openapi-typescript-codegen
- Wrapper layer maps generated services to clean namespaces
The SDK is regenerated from the Podium API’s OpenAPI spec whenever the API surface changes. Published versions on npm always reflect the latest API.
Versioning
The SDK follows semver. Breaking changes increment the major version:
npm install @podium-sdk/node-sdk@latest
Check the Podium API Playground for the latest endpoint documentation. The playground is always in sync with the production API.