Skip to content
Create API key

Products and recommendations

Bestsellers for a period, ranked by revenue. {range} takes any range token.

Param Default Notes
groupBy product product or category
category Filter to one category
limit 20 1 to 100
rep A sales rep code: only that rep’s sales (for rep portals)

Publishable keys receive rank, units and orders, with an aggregation floor: rows under 5 orders are left out. Secret keys also receive revenue and aov, with no floor.

Terminal
curl "https://api.plunk.io/cx/v1/products/top/this_month?limit=3" \
-H "Authorization: Bearer sk_live_••••"
Response (secret key)
{
"range": "this_month",
"groupBy": "product",
"keyClass": "secret",
"count": 3,
"items": [
{
"rank": 1,
"id": "SF-1042",
"title": "Harbor Sofa",
"category": "Sofas",
"units": 41,
"orders": 38,
"revenue": 61250.00,
"aov": 1611.84
}
]
}

The public product card, safe for a storefront. Never includes cost.

Response
{
"id": "SF-1042",
"title": "Harbor Sofa",
"category": "Sofas",
"price": 1899.00,
"salePrice": null,
"image": "https://…",
"link": "https://…",
"availability": "in stock",
"brand": "…"
}

An unknown id returns 404 product_not_found.

Semantic search. It matches on meaning rather than keywords, so “something for a small entryway” finds narrow console tables even when none of those words appear in a title. Results are then re-ranked by a blend of relevance, units sold and conversion rate, applied only among products that already matched.

Param Default Notes
q Required. What to search for, in plain language.
filter Optional keyword filter applied on top of the semantic match.
rank blended similarity returns pure semantic order, with no commercial weighting. Useful for comparing the two.
limit 20 1 to 100
Terminal
curl "https://api.plunk.io/cx/v1/products/search?q=dresser&limit=3" \
-H "Authorization: Bearer pk_live_••••"
Response
{
"query": "dresser",
"ranking": "blended",
"count": 3,
"items": [
{
"rank": 1,
"id": "…",
"title": "Carino Dresser - Frost",
"category": "Bedroom",
"link": "https://…",
"imageLink": "https://…",
"price": 1299.00,
"availability": "in stock",
"unitsSold": 24
}
]
}

What’s getting attention, which is a different question from /products/top/{range}. That one ranks by revenue actually booked. This one ranks by views, engagements, conversions or units from your site tracking.

Param Default Notes
range this_month Any range token. The default is deliberate: scoped to all_time, “trending” would mean “best ever” rather than “moving now”.
sort sales_quantity Or views, engagements, conversions.
filter Optional keyword filter.
limit 20 1 to 100
Response
{
"range": "this_month",
"sort": "views",
"count": 20,
"items": [
{ "rank": 1, "id": "…", "title": "Pacifico Dining Chair", "category": "Seating",
"link": "https://…", "imageLink": "https://…", "price": 449.00,
"availability": "in stock" }
]
}

“Customers also bought,” computed from real purchase history. Two endpoints: one counts co-occurrence live, the other reads a model rebuilt nightly. Scope recommendations:read covers both. They return rank and co-purchase evidence, never revenue.

Param Default Notes
product With it: products most often in the same order as this one. Without it: top sellers (a popular fallback).
limit 10 1 to 50
Response
{
"basis": "co_purchase",
"product": "SF-1042",
"count": 10,
"items": [
{
"rank": 1,
"id": "SF-1042-OTT",
"title": "Harbor Ottoman",
"category": "Ottomans",
"coPurchasedOrders": 19
}
]
}

The same question answered from a model rebuilt nightly instead of counted live. Prefer this one. The endpoint above counts products in the same order. This one counts distinct accounts that bought both over 24 months, weights each pair by how much evidence supports it, and keeps freight, fabric surcharges and card fees out of the results. Both are kept so existing integrations don’t change under you.

Param Default Notes
product What is bought alongside this product.
account What this account should buy next, excluding what it already owns.
contact A person id. Resolves to the account or accounts that contact belongs to and recommends across all of them. Pass exactly one of product, account or contact.
limit 10 1 to 50
Terminal
curl "https://api.plunk.io/cx/v1/recommendations/model?product=SF-1042&limit=3" \
-H "Authorization: Bearer pk_live_••••"
Response
{
"basis": "co_purchase_model",
"product": "SF-1042",
"account": null,
"count": 3,
"items": [
{
"rank": 1,
"id": "SF-1043",
"title": "Harbor Loveseat",
"category": "Seating",
"score": 0.594166,
"accounts": 22
}
]
}
  • score runs from 0 to 1; higher is stronger. accounts is how many accounts bought both.
  • An empty items array is a real answer, not an error. The product is new, has too little purchase history to be confident, or the model hasn’t been built for that catalog yet.
  • Sectional and modular goods often pair a product with its own mirror half (a left-facing piece with its right-facing twin), so two results can share a title while differing by SKU. That is the strongest signal in the data, not a duplicate. Render the SKU, not the title alone.
  • On ?product, score compares pairs across the whole catalog. On ?account it is scaled to the strongest hit in that response, so it ranks items within one answer and isn’t comparable between accounts.
Was this helpful?

Still stuck? Contact support and include the job or page you were on.