Skip to Content
GuidesShelf

Shelf

The shelf is the home screen of the app as an API: every product Skoup tracks for a brand on a market — every establishment for a local brand, every offer for a SaaS — with how the AI assistants treat it, already in the order to look at it. One call answers « which of my products is in trouble in the AI answers, and why? ».

A line is not a record of its own: its id is the product’s (prod_…) or the establishment’s (loc_…), so you can pass it to GET /v1/brands/{brand}/products/{product} or to the product’s perception. The shelf writes nothing.

Tracked = a product linked to at least one query of the market — cited in an answer, or close to a query by its category — cited or not. An active product linked to no query is not on the shelf (the app shows it as « not tracked » in the catalogue). During the trial, only the trial selection is tracked.

I want to…

I want to…Call
The shelf of a market, in orderGET /v1/brands/{brand}/shelf?market=FR
Only the products an assistant gets wrongGET /v1/brands/{brand}/shelf?q=is:error
The products no answer namesGET /v1/brands/{brand}/shelf?q=is:absent
The products that sell through the assistantsGET /v1/brands/{brand}/shelf?q=has:revenue
Where a competitor stands in front of youGET /v1/brands/{brand}/shelf?q=leader:"canyon"
What to fix on one productGET /v1/brands/{brand}/inbox?q=product:"Strade 7"

Scope: metrics:read (the shelf is a measure, not the catalogue). An assistant reads the same shelf with the MCP tool get_shelf.

The states

Skoup judges the state of each line — the same judge as the app, never a client-side rule. In the order they are listed:

errorreinforcegoodabsentunmeasured
Not a lifecycle: a line moves between states with each weekly sampling and each fix.
stateWhenstate_reason.kind
errorAn open alert about it (wrong price, wrong stock, invented spec, wrong address / phone / hours of an establishment), or a perception verdict judged false (a spec, the price…)alert (with alert_kind) · perception_false
absentIts queries were asked over the period, no answer named itnever_cited (count = its queries)
reinforceCited, but a differentiator of its sheet is missing from at least half of the answers judged about it, or its perception score is under 60usp_absent (label = the differentiator) · weak_perception (count = the score)
unmeasuredNo answer on its queries over the period yetnull
goodNone of the abovenull

state_reason.model is the assistant that said it most, element what is at fault (price, availability, spec, attribute, address…).

Order

Lines come sorted: what an assistant gets wrong, then what to reinforce, then the products the assistants cite; never-cited and never-measured lines come last. Within a state, the AI revenue of the period, then the share.

q takes the app’s search grammar:

QualifierValues
is:error, absent, reinforce, good, unmeasured
category:part of the category (the city of an establishment), e.g. category:"gravel"
model:cited at least once by chatgpt, claude, gemini, perplexity…
leader:part of the name or brand of the competitor cited first
has:revenue — an AI revenue over the period

- negates a qualifier (-is:good); anything else is free text on the title or the SKU.

Scenario: a weekly digest of the products in trouble

curl -G "https://api.skoup.ai/v1/brands/br_034PJIMnN3EOTCU3TMUdLS/shelf" \ --data-urlencode "market=FR" \ --data-urlencode "q=is:error" \ -H "Authorization: Bearer skoup_test_4eC39HqLyjWDarjtT1zdp7dc"

Run it after the weekly sampling.completed: each line says what is wrong (state_reason) and which assistant says it.

Pitfalls

  • No event. The shelf is computed when you call it. Follow the objects behind it: sampling.completed for the measure, alert.created for an error.
  • null is never 0. share is null for a line never measured; perception_score is null before enough judged answers; ai_revenue is null without store orders (or before the first order). Once orders flow, a product that sold nothing through an assistant has amount: 0.
  • delta compares the last two weekly cycles, share covers the whole period: they are not the same window.
  • by_model lists the measured models only. A model with no answer on the line’s queries is absent, never a row of zeros; trend has 12 weeks, oldest first, an empty by_model for a week without sampling.
  • Before the first completed sampling of the market, the list is empty.
  • Pagination is a cursor in the shelf’s order: limit (1–100, default 20) and starting_after = the id of the last line of the previous page. A new sampling reorders the shelf: start over rather than resume an old cursor.
Last updated on