Alerts, webhooks and files

Shelf, inside the tools your team already uses.

You do not have to open Shelf to hear from it. After each read, what moved for your brand and your rivals goes where your team already works: an inbox, a Slack channel, your own systems, a spreadsheet.

A drawing of one alert in three places. The product and the figures are made up.

Where it goes

How Shelf reaches your team.

One message per read, and none when nothing moved.

EmailEvery plan
A message after a read in which something moved for the brands you watch: which product, on which app, from what to what. Nothing is sent when nothing moved.
SlackFrom Pro
The same message, posted to a channel of yours through an incoming webhook you paste once.
Your own webhookOn Pro
Each alert posted as signed JSON to an https address of yours, so it can feed a spreadsheet, a dashboard or an automation without anyone copying it.
Excel and CSVOn Pro
Any table on screen as a file. Its first sheet says what was read, when, how many stores, and what each column means. Up to 300,000 rows a month.
A page to forwardIn the product
One page about your brand on one app, made to print or to send to a category manager.
WhatsAppNot live yet
You can save a number on Pro. Nothing is sent yet, and the product says so where you save it.

For your own systems

Your own webhook.

Give an alert an https address of yours and each alert is posted to it as JSON, signed so your side can check it came from us.

When a post is sent
After a read in which something moved for the brands the alert watches, as often as you chose. At most one post per read, and none when nothing moved.
What it holds
The read it is about, the brands, and up to 200 movements: the kind, the product, the app, the city, the prices in paise, and how many stores out of how many. “more” counts any beyond 200.
How you know it is from us
Every post carries x-shelf-signature. Its v1 is the HMAC-SHA256 of the timestamp, a full stop and the raw body, under the signing secret shown beside your alert. Check it before you trust the body.
What your endpoint should answer
Any 2xx status within eight seconds. We do not follow a redirect, and we do not read your answer beyond its status.
If it fails
The same read is tried again about an hour later. After 24 tries in a row that did not arrive, the alert is paused and you get one email saying so. Saving the alert again starts it from the latest read.
Which addresses are accepted
An https address on the standard port, with a public host name. An IP address, or an address inside a private network, is refused.
POST your endpointapplication/json
{
  "id": "0d6f6c2e-9a0b-4c57-8f1e-2f6a1f0f7b11",
  "type": "movements",
  "test": false,
  "sentAt": "<the moment it was sent, ISO 8601>",
  "read": { "build": "<the read's reference>", "fromMs": 1791244800000, "toMs": 1791504000000, "label": "<the read, in words>" },
  "brands": ["your-brand", "a-rival"],
  "count": 2,
  "atLeast": false,
  "movements": [
    {
      "kind": "price_down",
      "label": "Price cut",
      "platform": "blinkit",
      "sku": "123456",
      "name": "Product name 100 g",
      "brand": "a-rival",
      "city": "Pune",
      "storeId": null,
      "fromPricePaise": 6000,
      "toPricePaise": 5600,
      "stores": 41,
      "storesOutOf": 60,
      "cities": null,
      "readAtMs": 1791417600000,
      "line": "Price cut: Product name 100 g ₹60 to ₹56 on blinkit (Pune, 41 of 60 stores)"
    }
  ],
  "more": 0,
  "links": { "changes": "https://seetheshelf.com/feed", "alerts": "https://seetheshelf.com/alerts" }
}

Headers: content-type: application/json, x-shelf-event: movements, x-shelf-timestamp (Unix seconds) and x-shelf-signature: t=<the same seconds>,v1=<hex>. The names and figures above are made up; the shape is the real one.

Checking the signatureNode.js
import crypto from 'node:crypto';

// rawBody: the request body exactly as it arrived (a string or a Buffer), before any JSON parsing
export function isFromShelf(rawBody, header, secret) {
  const m = /^t=(\d+),v1=([a-f0-9]{64})$/.exec(header || '');
  if (!m) return false;
  // refuse a post that is more than five minutes old: it may be a replay
  if (Math.abs(Date.now() / 1000 - Number(m[1])) > 300) return false;
  const expected = crypto.createHmac('sha256', secret).update(m[1] + '.' + rawBody).digest('hex');
  return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(m[2]));
}

// isFromShelf(body, request.headers['x-shelf-signature'], process.env.SHELF_WEBHOOK_SECRET)
Checking the signaturePython
import hashlib, hmac, re, time

def is_from_shelf(raw_body: bytes, header: str, secret: str) -> bool:
    m = re.fullmatch(r"t=(\d+),v1=([a-f0-9]{64})", header or "")
    if not m:
        return False
    if abs(time.time() - int(m.group(1))) > 300:  # more than five minutes old: may be a replay
        return False
    signed = m.group(1).encode() + b"." + raw_body
    expected = hmac.new(secret.encode(), signed, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, m.group(2))

Compute it over the raw body, before parsing. The secret is the whole value shown beside your alert, starting whsec_.

For a spreadsheet

Excel and CSV.

Any table on screen, as a file that explains itself to someone who has never seen the product.

A drawing of an exported file. The first sheet of a real one says what was read, and when.
What a file holds
The rows of the table on screen, already cut to your plan, and a first sheet with the read it came from: the reference, the dates, the stores read, every caveat as a sentence, and a definition for every column.
How many
Up to 300,000 rows a month on Pro, and up to 50,000 rows in one file. The product shows what is left before you press Download, and the count starts again on the first of each month, India time.
Why files are counted
A file can be copied and passed on without the product, so a plan that includes files has a stated number of rows a month.
What you may do with it
© 2026 Apexlayer Technologies Private Limited. Licensed for use inside your business, including in reports to your own clients, with attribution to Shelf (seetheshelf.com). Not for resale as a dataset or bulk republication as a competing product without a written agreement.

Plans

What each plan includes

Email alerts are on every plan. These are the plan rows for this page.

What you getFreeno cardPro₹29,999 a month
Alerts when a price, a stock state or a listing changesEmailEmail, Slack, your own webhook. WhatsApp is not live yet
Excel and CSV of any tableNot on this planUp to 300,000 rows a month

Prices in rupees, per month, GST included. Pay once for 30 days, or turn on autopay and stop it any time. Compare every plan

Questions about alerts and files

Does Shelf have an API?

Not a public one. Everything is in Shelf once you sign up, and it has two ways out: alerts posted to your own webhook as signed JSON, and Excel or CSV of any table, both on Pro. A customer on a plan can ask for API access; we arrange it case by case.

Can alerts go to a Google Sheet or to Microsoft Teams?

Through your own webhook, yes: point the alert at an automation tool or a small script of yours, and let it write the rows wherever your team works. We post JSON; where it goes next is yours to decide.

How do I test a webhook?

Each alert has a “Send a test” button. It posts the movements of the latest read to your address, marked "test": true, and tells you the status your endpoint answered with.

What happens if my endpoint is down?

Nothing is lost on your screens. The post for that read is tried again about an hour later; after 24 tries in a row the alert is paused and you are told once by email.

Is there a limit on exports?

Yes, and it is stated: up to 300,000 rows a month on Pro, up to 50,000 rows a file. The Exports screen shows the month so far.

Do alerts need my seller login?

No. An alert is made from the same reads as the screens, which are read from the apps store by store.

See the shelf, every day.

Every store read every day. Pick a category and see who leads it, what sells out, who ranks in its searches and who pays for its ads. Free.

No card and no seller login needed.