Skip to main content
The Companion API provides the building blocks for personal shopping agents. It is vertical-agnostic — the Beauty Companion uses it for skincare, but the same endpoints power agents for any product domain.
Looking for the conversational AI agent? See Conversational Agent for the chat and streaming endpoints that combine these primitives into a full AI shopping companion with tool-use, memory, and proactive nudges.

Base Path

All endpoints are prefixed with /api/v1/companion.

Intent Profiles

An intent profile stores what a user wants — their preferences, constraints, and behavioral signals. Agents read and write profiles to personalize recommendations and execute purchases on a user’s behalf.

Create a Profile

curl -X POST https://api.podium.build/api/v1/companion/profile/{userId} \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "skinType": "Sensitive",
    "concerns": ["Anti-aging", "Hydration"],
    "priceRange": { "min": 75, "max": 150 },
    "brands": ["La Mer", "Drunk Elephant"],
    "avoidances": ["fragrance", "parabens"]
  }'
Response:
{
  "id": "clx9abc123def456",
  "userId": "clx7user789",
  "skinType": "Sensitive",
  "concerns": ["Anti-aging", "Hydration"],
  "priceRange": { "min": 75, "max": 150 },
  "brands": ["La Mer", "Drunk Elephant"],
  "avoidances": ["fragrance", "parabens"],
  "purchaseHistory": [],
  "podiumPoints": 0,
  "enrichmentVec": [],
  "quizCompletedAt": null,
  "createdAt": "2026-03-07T10:00:00Z",
  "updatedAt": "2026-03-07T10:00:00Z"
}

Get a Profile

curl https://api.podium.build/api/v1/companion/profile/{userId} \
  -H "Authorization: Bearer YOUR_API_KEY"

Update a Profile (Partial)

PATCH merges fields into the existing profile. Omitted fields are unchanged.
curl -X PATCH https://api.podium.build/api/v1/companion/profile/{userId} \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "concerns": ["Anti-aging", "Hydration", "Dark spots"],
    "priceRange": { "min": 50, "max": 200 }
  }'

Award Points

Points are stored on the intent profile and can be used for gamification, tier gating, or reward eligibility.
curl -X POST https://api.podium.build/api/v1/companion/profile/{userId}/points \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 25,
    "details": { "reason": "quiz_completed", "quizId": "onboarding_v2" }
  }'

Endpoints

MethodPathDescription
GET/companion/profile/{userId}Get user’s intent profile
POST/companion/profile/{userId}Create or replace intent profile
PATCH/companion/profile/{userId}Partial update (merge fields)
POST/companion/profile/{userId}/pointsAward points with metadata

Profile Schema

FieldTypeDescription
idstringCUID2 identifier
userIdstringCUID2 — the Podium user this profile belongs to
skinTypestring?Free-text preference dimension (use whatever fits your vertical)
concernsstring[]Array of preference tags
priceRangeobject?{ min: number, max: number } — budget constraints
brandsstring[]Preferred brands
avoidancesstring[]Things to exclude (ingredients, materials, etc.)
purchaseHistoryjson[]Server-managed purchase records
podiumPointsintegerCurrent point balance
enrichmentVecfloat[]Embedding vector for similarity matching (populated server-side)
quizCompletedAtdatetime?When the user completed an onboarding quiz
Profile fields like skinType, concerns, and avoidances are flexible string fields — they work for any product domain. A fashion agent might use bodyType, stylePreferences, and fabricAvoidances with the same schema structure.

Products

The Companion has its own product catalog (ProductCatalogItem) separate from the main commerce Product model. This lets agents curate a focused catalog from external sources without requiring products to exist in the core Podium commerce system.

List Products

curl "https://api.podium.build/api/v1/companion/products?category=moisturizer&minPrice=20&maxPrice=100&limit=10" \
  -H "Authorization: Bearer YOUR_API_KEY"
Query Parameters:
ParameterTypeDefaultDescription
categorystringFilter by category
brandstringFilter by brand
minPricenumberMinimum price
maxPricenumberMaximum price
inStockbooleanFilter by availability
searchstringFull-text search across name, brand, category
limitnumber20Results per page
offsetnumber0Pagination offset
Response:
[
  {
    "id": "clx9prod001",
    "name": "Hydrating Serum with Hyaluronic Acid",
    "brand": "The Ordinary",
    "category": "serum",
    "price": 12.90,
    "currency": "USD",
    "imageUrl": "https://cdn.example.com/products/serum.jpg",
    "productUrl": "https://theordinary.com/products/ha-serum",
    "openGraphData": { "title": "...", "description": "..." },
    "inStock": true,
    "createdAt": "2026-03-01T00:00:00Z"
  }
]

Get Product by ID

curl https://api.podium.build/api/v1/companion/products/{productId} \
  -H "Authorization: Bearer YOUR_API_KEY"

Create a Product

Agents or backend services can add products to the companion catalog:
curl -X POST https://api.podium.build/api/v1/companion/products \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "CeraVe Moisturizing Cream",
    "brand": "CeraVe",
    "category": "moisturizer",
    "price": 18.99,
    "imageUrl": "https://cdn.example.com/cerave-cream.jpg",
    "productUrl": "https://cerave.com/moisturizing-cream"
  }'

Batch Create Products

Add up to 100 products in a single request:
curl -X POST https://api.podium.build/api/v1/companion/products/batch \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "items": [
      {
        "name": "CeraVe Moisturizing Cream",
        "brand": "CeraVe",
        "category": "moisturizer",
        "price": 18.99,
        "productUrl": "https://cerave.com/moisturizing-cream"
      },
      {
        "name": "La Roche-Posay Toleriane",
        "brand": "La Roche-Posay",
        "category": "cleanser",
        "price": 15.99,
        "productUrl": "https://laroche-posay.com/toleriane"
      }
    ]
  }'

Product Schema

FieldTypeRequiredDescription
namestringYesProduct name (max 500 chars)
brandstringYesBrand name
categorystringYesProduct category
pricenumberYesPrice as a decimal (e.g., 18.99)
currencystringNoISO currency code (default: USD)
imageUrlstringNoProduct image URL
productUrlstringYesCanonical product page URL
openGraphDataobjectNoOpenGraph metadata from the product page
inStockbooleanNoAvailability (default: true)

Endpoints

MethodPathDescription
GET/companion/productsList products (filterable, paginated)
GET/companion/products/{productId}Get single product
POST/companion/productsCreate one product
POST/companion/products/batchBatch create (1–100 items)

Interactions

Interactions record how a user engages with products. They power the recommendation engine and form the behavioral signal layer of the intent profile.

Record an Interaction

curl -X POST https://api.podium.build/api/v1/companion/interactions \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "userId": "clx7user789",
    "productId": "clx9prod001",
    "action": "RANK_UP",
    "score": 0.9
  }'

Get User Interactions

curl https://api.podium.build/api/v1/companion/interactions/{userId} \
  -H "Authorization: Bearer YOUR_API_KEY"

Interaction Types

ActionMeaningSignal Strength
RANK_UPUser likes/loves the productStrong positive
RANK_DOWNUser dislikes the productStrong negative
SKIPUser skipped (neutral)Weak negative
PURCHASEDUser completed a purchaseStrongest positive
PURCHASE_INTENTUser started but didn’t completeModerate positive
NUDGE_OPENEDUser opened a proactive notificationWeak positive

Interaction Schema

FieldTypeRequiredDescription
userIdstringYesThe user performing the action
productIdstringYesThe product being acted on
actionenumYesOne of the six interaction types above
scorenumberNoOptional 0–1 confidence score

Endpoints

MethodPathDescription
POST/companion/interactionsRecord an interaction
GET/companion/interactions/{userId}Get all interactions for a user

Recommendations

The recommendation engine uses AI-powered ranking to score products based on a user’s intent profile and interaction history. It returns products the user hasn’t interacted with, scored by relevance to their declared preferences and behavioral signals.

Get Recommendations

curl "https://api.podium.build/api/v1/companion/recommendations/{userId}?count=5&category=serum" \
  -H "Authorization: Bearer YOUR_API_KEY"
Query Parameters:
ParameterTypeDefaultDescription
countnumber5Number of recommendations to return
categorystringOptional category filter
Response:
[
  {
    "id": "clx9prod042",
    "name": "Drunk Elephant Protini Polypeptide Cream",
    "brand": "Drunk Elephant",
    "category": "moisturizer",
    "price": 68.00,
    "imageUrl": "https://cdn.example.com/de-protini.jpg",
    "productUrl": "https://drunkelephant.com/protini",
    "inStock": true
  }
]
Recommendations exclude products the user has already interacted with (any action type). The engine considers RANK_UP and PURCHASED interactions as positive signals for similar products, and RANK_DOWN as negative signals for similar attributes.

Endpoints

MethodPathDescription
GET/companion/recommendations/{userId}AI-ranked product recommendations

Orders

Companion orders use a concierge fulfillment model — the user pays Podium (via x402 USDC or Stripe), and the platform handles purchasing from the retailer and shipping to the user. This enables agents to execute purchases from any catalog source, not just products that exist in Podium’s core commerce system. The conversational agent’s create_order tool uses these endpoints automatically during chat — see Conversational Agent for the full flow.

Create a Concierge Order

curl -X POST https://api.podium.build/api/v1/companion/orders \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "userId": "clx7user789",
    "productId": "clx9prod042",
    "shippingAddress": {
      "street": "123 Main St",
      "city": "San Francisco",
      "state": "CA",
      "zip": "94102",
      "country": "US"
    },
    "email": "user@example.com"
  }'
Response:
{
  "id": "clx9order001",
  "userId": "clx7user789",
  "productId": "clx9prod042",
  "status": "PENDING_PAYMENT",
  "shippingAddress": {
    "street": "123 Main St",
    "city": "San Francisco",
    "state": "CA",
    "zip": "94102",
    "country": "US"
  },
  "email": "user@example.com",
  "productSnapshot": {
    "name": "Drunk Elephant Protini Polypeptide Cream",
    "brand": "Drunk Elephant",
    "price": 68.00,
    "imageUrl": "https://cdn.example.com/de-protini.jpg"
  },
  "amountUsdc": "68.00",
  "createdAt": "2026-03-07T12:00:00Z"
}

List User Orders

curl https://api.podium.build/api/v1/companion/orders/{userId} \
  -H "Authorization: Bearer YOUR_API_KEY"

Get Order Detail

curl https://api.podium.build/api/v1/companion/orders/detail/{orderId} \
  -H "Authorization: Bearer YOUR_API_KEY"

Update Order Status

curl -X PATCH https://api.podium.build/api/v1/companion/orders/{orderId}/status \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "status": "SHIPPED",
    "fulfillmentNotes": "USPS tracking: 9400111899223456789012"
  }'

Order Status Flow

StatusDescription
PENDING_PAYMENTOrder created, awaiting payment via x402 USDC or Stripe
PAIDPayment confirmed
FULFILLINGPlatform purchasing from retailer
SHIPPEDShipped to user
DELIVEREDDelivery confirmed
CANCELLEDOrder cancelled
REFUNDEDPayment refunded

Order Schema

FieldTypeDescription
idstringCUID2 identifier
userIdstringThe user who placed the order
productIdstringCompanion catalog product
statusenumCurrent order status
shippingAddressobject{ street, city, state, zip, country }
emailstringNotification email
productSnapshotobjectFrozen product data at time of order
amountUsdcstringOrder amount in USDC (string for precision)
fulfillmentNotesstring?Tracking numbers, notes
podiumOrderIdstring?Linked core Podium order (if bridged)

Endpoints

MethodPathDescription
POST/companion/ordersCreate a concierge order
GET/companion/orders/{userId}List user’s orders (newest first)
GET/companion/orders/detail/{orderId}Order detail with product
PATCH/companion/orders/{orderId}/statusUpdate status and fulfillment notes

Chat History

Retrieve durable conversation history for a user. Messages include role, content, timestamps, and any product cards that were shown during the conversation.

Get Chat History

curl "https://api.podium.build/api/v1/companion/agent/chat/history/{userId}?limit=50" \
  -H "Authorization: Bearer YOUR_API_KEY"
Query Parameters:
ParameterTypeDefaultDescription
limitnumber50Number of messages to return
beforestringMessage ID cursor for pagination (returns messages older than this ID)
Response:
[
  {
    "id": "msg_clxyz001",
    "role": "user",
    "content": "What's a good moisturizer for sensitive skin under $50?",
    "timestamp": "2026-03-07T14:30:00Z"
  },
  {
    "id": "msg_clxyz002",
    "role": "assistant",
    "content": "Based on your profile, I'd recommend the CeraVe Moisturizing Cream...",
    "timestamp": "2026-03-07T14:30:02Z",
    "products": [
      {
        "id": "clx9prod001",
        "name": "CeraVe Moisturizing Cream",
        "brand": "CeraVe",
        "price": 18.99,
        "imageUrl": "https://cdn.example.com/cerave-cream.jpg"
      }
    ]
  }
]

Message Schema

FieldTypeDescription
idstringUnique message identifier (use as before cursor for pagination)
rolestringuser or assistant
contentstringMessage text
timestampstringISO 8601 timestamp
productsobject[]?Product cards shown with this message (assistant messages only)

Endpoints

MethodPathDescription
GET/companion/agent/chat/history/{userId}Paginated chat history
Pagination is cursor-based. Pass the id of the oldest message in your current page as the before parameter to fetch the next page. An empty array indicates no more history.

Creator Products

Retrieve the resolved product catalog for a creator persona. Creator personas are profiles that curate products based on a creator’s taste, platform affiliation, and audience — used by apps like Clone Agents (Familiar).

Get Creator Products

curl https://api.podium.build/api/v1/companion/creator/{handle}/products \
  -H "Authorization: Bearer YOUR_API_KEY"
Response:
{
  "items": [
    {
      "id": "clx9prod042",
      "name": "Drunk Elephant Protini Polypeptide Cream",
      "brand": "Drunk Elephant",
      "category": "moisturizer",
      "price": 68.00,
      "imageUrl": "https://cdn.example.com/de-protini.jpg",
      "productUrl": "https://drunkelephant.com/protini",
      "inStock": true
    }
  ],
  "creatorHandle": "janedoe",
  "displayName": "Jane Doe"
}
FieldTypeDescription
itemsobject[]Array of resolved product catalog items
creatorHandlestringThe creator’s unique handle
displayNamestringThe creator’s display name

Endpoints

MethodPathDescription
GET/companion/creator/{handle}/productsGet a creator’s curated product catalog

Profile Seeding from Creator

Merge a creator’s taste profile — preferred brands, price ranges, product concerns — into a user’s intent profile. This lets users bootstrap their preferences from a creator they trust, without going through a full onboarding quiz.

Seed Profile from Creator

curl -X POST https://api.podium.build/api/v1/companion/profile/{userId}/seed-from-creator \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "creatorHandle": "janedoe"
  }'
Behavior:
  • Merges the creator’s brand preferences, price range, and concern tags into the user’s intent profile
  • Does not overwrite user-set fields if the user has completed an onboarding quiz (i.e., quizCompletedAt is set)
  • Safe to call multiple times — subsequent calls merge additively

Endpoints

MethodPathDescription
POST/companion/profile/{userId}/seed-from-creatorSeed user profile from creator taste data

Subscription Endpoints

The subscription system handles billing, usage tracking, and tier management for companion agents. For full documentation — including tiers, usage gating, memory gating, and integration examples — see Subscriptions.
MethodPathDescription
POST/companion/subscription/checkoutCreate a Stripe checkout session
POST/companion/subscription/portalOpen Stripe customer portal
GET/companion/subscription/{userId}/statusGet subscription status and usage

User Linking

Connect external platform users (e.g., Telegram) to Podium users. The companion looks up users by a synthetic email pattern.
curl "https://api.podium.build/api/v1/companion/user/by-telegram/{telegramId}?privyId=did:privy:abc123" \
  -H "Authorization: Bearer YOUR_API_KEY"
ParameterTypeDescription
telegramIdstring (path)Telegram user ID
privyIdstring (query, optional)Privy DID to link to the user
The lookup uses a synthetic email pattern: tg_{telegramId}@beauty-companion.podium.app. If a matching user exists, it’s returned. If privyId is provided, the Privy DID is linked to the user record.

Building an Agent: End-to-End Flow

Here’s the typical lifecycle of a companion agent interaction:
1

Onboard the User

Create an intent profile with the user’s stated preferences. This can come from a quiz, conversation, or imported data.
import { createPodiumClient } from '@podium-sdk/node-sdk'
const client = createPodiumClient({ apiKey: process.env.PODIUM_API_KEY })

const { data: profile } = await client.companion.createProfile({
  userId,
  requestBody: {
    concerns: ["Hydration", "Anti-aging"],
    priceRange: { min: 30, max: 100 },
    avoidances: ["fragrance"],
  },
})
2

Get Recommendations

The engine uses the profile + interaction history to rank products with AI-powered relevance scoring.
const { data: recs } = await client.companion.listRecommendations({
  userId,
  count: 5,
})
3

Present and Record Feedback

Show recommendations to the user. Record their reactions as interactions.
await client.companion.createInteractions({
  requestBody: {
    userId,
    productId: recs[0].id,
    action: "RANK_UP",
  },
})
4

Execute Purchase

When the user approves, create a concierge order. Payment can be processed via x402 (USDC) or linked to a Stripe checkout.
const { data: order } = await client.companion.createOrders({
  requestBody: {
    userId,
    productId: recs[0].id,
    shippingAddress: userAddress,
    email: userEmail,
  },
})
5

Refine Over Time

Each interaction improves future recommendations. The enrichmentVec on the profile is updated server-side as the user’s pattern emerges. Award points for engagement to drive retention.
await client.companion.createProfilePoints({
  userId,
  requestBody: {
    amount: 10,
    details: { reason: "feedback_given" },
  },
})