Edge Recommendation API Reference
Real-time product-recommendation endpoints served at the CDN edge. Most are
CloudFront Functions that synthesize a JSON response from a KeyValueStore on every
viewer request (no origin fetch); two are DMP-backed Lambdas fronted by a caching
distribution. All are GET, anonymous, and CORS-open (Access-Control-Allow-Origin: *).
Every endpoint also answers OPTIONS with 204 for CORS preflight.
Endpoints marked ?render=html can return a human-readable
HTML card view instead of JSON.
https://addon-reco.cscbandit.comhttps://reco-cdn.cscbandit.com/{brand}/v1/
Walk-mode add-on pick
Single best add-on for a cart, found by walking a slugified category hierarchy leaf→root until a co-purchase list matches. `{brand}` is a registered brand prefix (e.g. `bc` = Backcountry).
Base https://addon-reco.cscbandit.com Cache-Control no-store
Query parameters
| Param | Type | Notes | |
|---|---|---|---|
sku repeatable |
required | string |
Cart item styleids. URL-decoded (`+` = space). First value is the anchor. |
category repeatable |
required | string |
Category hierarchy, root→leaf, one repeated param per level. Walked leaf→root for the first match. |
Example request
GET https://addon-reco.cscbandit.com/bc/v1/?sku=XYZ789&category=Bikes&category=Road%20Bikes
Response (application/json; charset=utf-8)
{
"recommendation": {
"addon": {
"styleid": "ABC123",
"stylename": "Trail Jacket",
"brandname": "Acme",
"style_color": "ABC123-RED",
"picked_sku": "ABC123-RED-M",
"current_price": 49.99,
"on_hand": 5,
"styleid_on_hand_total": 12,
"lift": 2.5,
"n_cooccur": 100,
"n_addon_orders": 45
},
"anchorStyleid": "XYZ789",
"anchorCategoryName": "Road Bikes",
"anchorSlug": "road-bikes",
"matchLevel": "leaf"
},
"brand": "bc"
}
Errors
| Status | When |
|---|---|
400 | Missing `sku` or `category`. |
404 | Unknown brand prefix (not in brands.ts). |
405 | Method other than GET/OPTIONS. |
500 | No data source configured for the brand. |
/{brand}/v1/cat/{slug}
Path-mode add-on pick
Same pick as walk-mode but the anchor category is taken from the URL path (`{slug}`) instead of repeated `category=` params. Used by CC (`/cc/v1/cat/
Base https://addon-reco.cscbandit.com Cache-Control no-store
Query parameters
| Param | Type | Notes | |
|---|---|---|---|
sku repeatable |
required | string |
Cart item styleids. At least one required. |
Example request
GET https://addon-reco.cscbandit.com/cc/v1/cat/road-shoes?sku=ABC123
Response (application/json; charset=utf-8)
{
"recommendation": { "addon": { "styleid": "ABC123", "picked_sku": "ABC123-RED-M", "current_price": 49.99, "...": "see walk-mode" }, "matchLevel": "leaf" },
"brand": "cc"
}
Errors
| Status | When |
|---|---|
400 | Missing `sku`. |
404 | Unknown brand prefix. |
405 | Method other than GET/OPTIONS. |
/cc/v2/ ?render=html
Persona fast-path add-on
Single add-on chosen by a persona model (cart slugs/brands/discipline → cluster → predicate pick), falling back to the v1 co-purchase pick on a miss.
Base https://addon-reco.cscbandit.com Cache-Control no-store
Query parameters
| Param | Type | Notes | |
|---|---|---|---|
sku repeatable |
required | string |
Cart item styleids. |
slug repeatable |
required | string |
Union of cart item slug ancestors. |
brand repeatable |
optional | string |
Distinct brands on cart items. |
discipline repeatable |
optional | string |
Top-level discipline tokens (e.g. 'road', 'mtb', 'gravel'). |
priceTier |
optional | 'low'|'mid'|'premium'|'flagship' default: low |
Price tier of the cart. |
cartSize |
optional | integer default: sku count |
Distinct styleids in cart. |
render |
optional | 'html' |
Return a self-contained HTML card view instead of JSON. |
Example request
GET https://addon-reco.cscbandit.com/cc/v2/?sku=ABC123&slug=road-shoes&priceTier=premium
Response (application/json; charset=utf-8)
{
"recommendation": {
"addon": {
"rank": 1,
"styleid": "ABC123",
"picked_sku": "ABC123-RED-M",
"style_color": "ABC123-RED",
"current_price": 79.99,
"on_hand": 10,
"source": "persona"
},
"anchorStyleid": "XYZ789",
"pick_via": "predicate",
"cluster_id": 42,
"persona_label": "Weekend Roadie"
},
"brand": "cc"
}
Errors
| Status | When |
|---|---|
400 | Missing `sku` or `slug`. |
404 | Unknown path. |
405 | Method other than GET/OPTIONS. |
/cc/v2/cart-filler/ ?render=html
Free-shipping cart filler
Picks one add-on priced inside a band above the current cart total — to nudge the shopper over a free-shipping / promo threshold. Band = [gap, gap × ceiling).
Base https://addon-reco.cscbandit.com Cache-Control no-store
Query parameters
| Param | Type | Notes | |
|---|---|---|---|
sku repeatable |
required | string |
Cart item styleids. |
slug repeatable |
required | string |
Cart item slug ancestors. |
gap |
required | number |
Dollars remaining to the threshold. Must be finite and > 0, else no pick. |
ceiling |
optional | number default: 2 |
Upper band multiplier. Clamped to (1, 10]. |
brand repeatable |
optional | string |
Distinct brands on cart items. |
discipline repeatable |
optional | string |
Top-level discipline tokens. |
priceTier |
optional | 'low'|'mid'|'premium'|'flagship' default: low |
Price tier of the cart. |
cartSize |
optional | integer default: sku count |
Distinct styleids in cart. |
render |
optional | 'html' |
HTML card view instead of JSON. |
Example request
GET https://addon-reco.cscbandit.com/cc/v2/cart-filler/?sku=ABC123&slug=road-shoes&gap=25&ceiling=2
Response (application/json; charset=utf-8)
{
"pick": {
"styleid": "ABC123",
"picked_sku": "ABC123-RED-M",
"stylename": "Ride Socks",
"brandname": "Acme",
"current_price": 32.00,
"on_hand": 3,
"lift": 1.8,
"style_color": "ABC123-RED"
},
"pick_via": "persona",
"cluster_id": 42,
"persona_label": "Weekend Roadie",
"gap": 25.00,
"band": { "min": 25.00, "max": 50.00 },
"brand": "cc"
}
Errors
| Status | When |
|---|---|
400 | Missing required params or invalid `gap`. |
404 | Unknown path. |
405 | Method other than GET/OPTIONS. |
/cc/v3/ ?render=html
Ranked add-on list
Returns an ordered array of add-ons (persona predicate picks first, then slug lookups, then v1 fallback), deduped against the cart.
Base https://addon-reco.cscbandit.com Cache-Control no-store
Query parameters
| Param | Type | Notes | |
|---|---|---|---|
sku repeatable |
required | string |
Cart item styleids. |
slug repeatable |
required | string |
Cart item slug ancestors. |
max |
optional | integer default: 5 |
Max recommendations. Hard cap 10. |
brand repeatable |
optional | string |
Distinct brands. |
discipline repeatable |
optional | string |
Top-level discipline tokens. |
priceTier |
optional | 'low'|'mid'|'premium'|'flagship' default: low |
Price tier of the cart. |
cartSize |
optional | integer default: sku count |
Distinct styleids in cart. |
render |
optional | 'html' |
HTML card view instead of JSON. |
Example request
GET https://addon-reco.cscbandit.com/cc/v3/?sku=ABC123&slug=road-shoes&max=10
Response (application/json; charset=utf-8)
{
"recommendations": [
{
"addon": { "rank": 1, "styleid": "ABC123", "picked_sku": "ABC123-RED-M", "current_price": 89.99, "source": "persona" },
"pick_via": "predicate",
"cluster_id": 42,
"persona_label": "Weekend Roadie"
}
],
"anchorStyleid": "XYZ789",
"max": 5,
"brand": "cc"
}
Errors
| Status | When |
|---|---|
400 | Missing `sku` or `slug`. |
404 | Unknown path. |
405 | Method other than GET/OPTIONS. |
/cc/ctl/v1/{styleid} ?render=html
Complete-the-look outfit
Precomputed "complete the look" outfit for a PDP styleid: the main item plus matching items (by type/category) with candidate products each.
Base https://addon-reco.cscbandit.com Cache-Control no-store
Query parameters
| Param | Type | Notes | |
|---|---|---|---|
render |
optional | 'html' |
HTML view instead of JSON. |
Example request
GET https://addon-reco.cscbandit.com/cc/ctl/v1/ABC123?render=html
Response (application/json; charset=utf-8)
{
"styleid": "ABC123",
"status": "ok",
"basis": "on-model",
"main": { "styleid": "ABC123", "name": "Race Jersey", "brand": "Acme", "color": "Red", "category": "Jerseys", "gender": "Men's" },
"detection_images": ["https://content.competitivecyclist.com/..."],
"items": [
{
"type": "Shorts", "category": "Bottoms", "color": "Black", "gender": "Men's", "match_count": 3,
"products": [
{ "uniqueId": "prod123", "brand": "Acme", "title": "Bib Shorts", "price": 159.99, "productUrl": "https://...", "imageUrl": "https://..." }
]
}
]
}
Errors
| Status | When |
|---|---|
404 | No look computed for the styleid. |
405 | Method other than GET/OPTIONS. |
/cc/oh/v1/ ?render=html
Cross-order recommendations
Blends two cross-order signals: replenishment picks for owned consumables that are "due", then next-purchase styles bought after owning the cart's categories. Replenish picks lead.
Base https://addon-reco.cscbandit.com Cache-Control no-store
Query parameters
| Param | Type | Notes | |
|---|---|---|---|
sku repeatable |
required | string |
Owned styleids from recent orders. |
slug repeatable |
required | string |
Owned category slugs (seo_url_token). |
daysSince repeatable |
optional | integer |
Days since purchase, aligned positionally with `sku`. Without it an item is never "due". |
max |
optional | integer default: 5 |
Total recommendation cap. Hard cap 10. |
maxReplenish |
optional | integer default: 2 |
Cap on replenish picks placed first. |
render |
optional | 'html' |
HTML view instead of JSON. |
Example request
GET https://addon-reco.cscbandit.com/cc/oh/v1/?sku=ABC123&sku=DEF456&slug=road-shoes&daysSince=45&daysSince=30&max=5
Response (application/json; charset=utf-8)
{
"recommendations": [
{ "styleid": "ABC123", "rep_sku": "ABC123-RED-M", "current_price": 19.99, "tier": "replenish", "due_ratio": 1.5, "group": "chamois-cream" },
{ "styleid": "DEF456", "rep_sku": "DEF456-BLK-L", "current_price": 129.99, "tier": "next-purchase", "lift": 2.3 }
],
"anchorStyleid": "ABC123",
"max": 5,
"brand": "cc"
}
Errors
| Status | When |
|---|---|
400 | Missing `sku` or `slug`. |
404 | Unknown path. |
405 | Method other than GET/OPTIONS. |
/cc/{buyer-selected|alan-selected}/v1/ ?render=html
Static curated pick map
Two hand-curated category→sku maps baked into the bundle (no KVS, no I/O), backing the CC mini-cart "People Also Bought" A/B test: `buyer-selected` (merch picks, Variant 1) and `alan-selected` (Variant 0). With `slug`, returns one pick; without, dumps the whole map.
Base https://addon-reco.cscbandit.com Cache-Control no-store
Query parameters
| Param | Type | Notes | |
|---|---|---|---|
slug |
optional | string |
Category slug to look up. Omit to dump the full map. |
render |
optional | 'html' |
Debug table view instead of JSON. |
Example request
GET https://addon-reco.cscbandit.com/cc/buyer-selected/v1/?slug=road-shoes
Response (application/json; charset=utf-8)
// with ?slug=road-shoes
{ "variant": "buyer-selected", "slug": "road-shoes", "picked_sku": "ABC123" }
// without slug
{ "variant": "buyer-selected", "count": 124, "map": { "road-shoes": "ABC123", "mtb-pedals": "XYZ789" } }
Errors
| Status | When |
|---|---|
404 | Unknown path. |
405 | Method other than GET/OPTIONS. |
/bc/v1/addons ?render=html
Add-on assignments
Live add-on assignments from the DMP (`sku_bc_addon_assignments`) for one or more parent SKUs. Edge-cached on the `cdn/` distribution; each cache miss is a signed SQL round-trip to DMP.
Base https://reco-cdn.cscbandit.com Cache-Control public, max-age=300 (success); no-store (errors)
Query parameters
| Param | Type | Notes | |
|---|---|---|---|
sku repeatable |
required | string |
Parent SKUs. De-duped, order preserved. Max 50; blanks ignored. |
account |
optional | string default: bc |
DMP account id. |
render |
optional | 'html' |
HTML view instead of JSON. |
Example request
GET https://reco-cdn.cscbandit.com/bc/v1/addons?sku=SKU1&sku=SKU2&account=bc
Response (application/json; charset=utf-8)
{
"account": "bc",
"requested": ["SKU1", "SKU2"],
"results": [
{ "parentSku": "SKU1", "addons": [ { "addOnSku": "ADDON-SKU", "slot": 1, "source": "affinity-model", "createdAt": "2025-01-15T10:00:00Z" } ] }
],
"count": 3,
"timing_ms": { "total": 145.5 }
}
Errors
| Status | When |
|---|---|
400 | No `sku`, or more than 50 SKUs. |
405 | Method other than GET/OPTIONS. |
502 | DMP query failed. |
/bc/v1/complements ?render=html
Knowledge-graph complements
Complementary products from the DMP product knowledge graph (edge or projection source) for one or more source styleids. Edge-cached on the `cdn/` distribution.
Base https://reco-cdn.cscbandit.com Cache-Control public, max-age=300 (success); no-store (errors)
Query parameters
| Param | Type | Notes | |
|---|---|---|---|
sku repeatable |
required | string |
Source styleids. De-duped, order preserved. Max 50; blanks ignored. |
brand |
optional | string default: bc |
Brand code for node-id hashing. |
limit |
optional | integer default: 10 |
Complements per SKU. Clamped to [1, 50]. |
render |
optional | 'html' |
HTML view instead of JSON. |
Example request
GET https://reco-cdn.cscbandit.com/bc/v1/complements?sku=SKU1&sku=SKU2&brand=bc&limit=10
Response (application/json; charset=utf-8)
{
"brand": "bc",
"requested": ["SKU1"],
"limit": 10,
"results": [
{
"sku": "SKU1",
"source": "edges",
"complements": [
{ "weight": 0.85, "confidence": 0.92, "sharedActivities": ["road-cycling"], "source": "edges", "detail": { "styleid": "COMP-SKU", "name": "..." } }
]
}
],
"count": 15,
"timing_ms": { "total": 234.2 }
}
Errors
| Status | When |
|---|---|
400 | No `sku`, or more than 50 SKUs. |
405 | Method other than GET/OPTIONS. |
502 | DMP query failed. |