Skip to content
StoreProfiles

Developers · read-only

Registry API.

Everything the registry publishes — store profiles, trust scores with per-component breakdowns, catalogs and daily history — is available as JSON, CSV, RSS and SVG. No keys, no signup, CORS open. Published under CC BY 4.0 — reuse it, including commercially, and credit the registry with a link to the store profile.

The data itself — field dictionary, cadence, limits, citation: /dataset · Score methodology: /how-we-score · machine summary for AI crawlers: /llms.txt

GET/api

API index: lists the available endpoints, their parameters and the usage terms.

endpoints.registry.params
accepted query params for /api/registry: page (integer, default 1) and niche (beauty-skincare | fashion | supplements | home-kitchen | food-drink).
id
the store slug — the stable key for a record. Use this to reference a store.
code
display label only (BTY-0042). The prefix follows the niche, so it changes if a store is recategorised — never key on it.
terms
CC BY 4.0 — free to use, including commercially, with attribution: a link to the store profile.
rate limits
Read endpoints are unmetered; they are edge-cached, so polling them costs you latency rather than access. /api/suggest is the exception — it runs a live query per keystroke and is capped per IP, returning 429 with Retry-After: 10 when you exceed it. Honour Retry-After rather than retrying immediately; there is no key to raise, and no limit that a paid plan would lift, because there are no plans.
stability
Field names and shapes are additive: new fields may appear, existing ones are not renamed or removed without a version note. The scoring formula is versioned separately — trust_score and every history row carry rules_version, and what each version changed is listed on /changelog. Current: rules v0.8.

shape example (truncated)

{
  "name": "StoreProfiles Registry API",
  "description": "Public, read-only access to the independent registry…",
  "endpoints": {
    "registry": {
      "url": "https://storeprofiles.com/api/registry",
      "params": {
        "page": "integer, default 1 (50 per page)",
        "niche": "beauty-skincare | fashion | supplements | home-kitchen | food-drink"
      }
    },
    "store": { "url": "https://storeprofiles.com/api/store/{slug}" }
  },
  "terms": "CC BY 4.0 — attribution: link to the store profile"
}

GET/api/registry

Paginated list of every store on record, 50 per page, ranked by trust score. Filters: ?page=2, ?niche=fashion.

meta
total (count of live stores), page, per_page (50), niche (null when unfiltered).
stores[].code
registry record code — niche prefix + id, e.g. BTY-0042. Display-only, stable.
stores[].claimed
true once the owner verified domain control via meta tag. Adds +15 to the score (rules v0.8), never editing rights.
stores[].trust_score
integer 0–100, computed from the store's public product feed. Null while the first audit is in preparation.
stores[].profile / api
canonical URLs of the human profile page and this store's JSON endpoint.

shape example (truncated)

{
  "meta": { "total": 599, "page": 1, "per_page": 50, "niche": null },
  "stores": [
    {
      "code": "BTY-0042",
      "slug": "example-beauty",
      "name": "Example Beauty Co.",
      "domain": "examplebeauty.com",
      "niche": "beauty-skincare",
      "claimed": false,
      "trust_score": 78,
      "product_count": 100,
      "profile": "https://storeprofiles.com/store/example-beauty",
      "api": "https://storeprofiles.com/api/store/example-beauty",
      "updated_at": "2026-07-18T04:12:09.000Z"
    }
  ]
}

GET/api/store/{slug}

One store in full: profile, score breakdown, catalog stats, AI audit, up to 12 products and daily history. 404 { "error": "not_on_record" } for unknown or dead stores.

verdict
a ready-to-quote sentence answering "is {store} legit": the trust score plus the strongest pro and main caveat, computed from public data. Null before the first audit. Same text the profile exposes to answer engines.
niche_percentile
the store's standing among audited peers in its niche, 0–100 ("higher than N% of niche stores"). Null when the niche has fewer than 8 scored stores.
score_breakdown
the trust-score receipt, one {got, max} pair per component: on_record (5), catalog_depth (≤25), images (≤15), descriptions (≤12), pricing_data (≤8), claimed (15) plus verified_signals (≤20), the verified tier from collected external facts (policies, reviews, speed). The maxima sum to exactly 100 and the components sum to trust_score — no separate cap since rules v0.7, and since v0.8 verified_signals is only added when the catalog clears a quality bar. Same formula as /how-we-score.
catalog
product_count plus min_price, avg_price and currency computed from priced products only.
review
latest versioned AI audit: model, version, pros/cons (each point cites its source), who_for, created_at. Null before the first audit.
owner_response
the owner's public reply to the audit ({text, at}), or null. Replying never edits the audit itself.
top_products
up to 12 products: title, price, currency, image_url, url, product_type.
history
daily snapshots (up to 365): day (YYYY-MM-DD), product_count, avg_price, min_price, trust_score, rules_version — chart-ready trend data. Compare trust_score only across snapshots sharing a rules_version: a formula change is our step, not the store's.
partner_program
{active: false}, or {active: true, commission_pct, notes} once the owner enabled it in the dashboard.

shape example (truncated)

{
  "code": "BTY-0042",
  "slug": "example-beauty",
  "name": "Example Beauty Co.",
  "domain": "examplebeauty.com",
  "niche": "beauty-skincare",
  "claimed": false,
  "profile": "https://storeprofiles.com/store/example-beauty",
  "badge": "https://storeprofiles.com/badge/example-beauty",
  "trust_score": 64,
  "verdict": "Is Example Beauty Co. legit? Yes — independent trust score 64/100, computed from public data, not paid reviews. Strongest signal: deep catalog…",
  "niche_percentile": 74,
  "score_breakdown": {
    "on_record":         { "got": 5,  "max": 5 },
    "catalog_depth":     { "got": 21, "max": 25 },
    "images":            { "got": 13, "max": 15 },
    "descriptions":      { "got": 9,  "max": 12 },
    "pricing_data":      { "got": 8,  "max": 8 },
    "claimed":           { "got": 0,  "max": 15 },
    "verified_signals":  { "got": 8,  "max": 20 }
  },
  "catalog": {
    "product_count": 100,
    "min_price": "9.00",
    "avg_price": "24.85",
    "currency": "USD"
  },
  "review": {
    "model": "claude-sonnet",
    "version": 3,
    "pros": [{ "point": "…", "source": "products.json" }],
    "cons": [{ "point": "…", "source": "products.json" }],
    "who_for": "…",
    "created_at": "2026-07-15T02:00:11.000Z"
  },
  "owner_response": null,
  "top_products": [
    {
      "title": "Vitamin C Serum",
      "price": "24.00",
      "currency": "USD",
      "image_url": "https://cdn.shopify.com/…/serum.jpg",
      "url": "https://examplebeauty.com/products/vitamin-c-serum",
      "product_type": "Serum"
    }
  ],
  "history": [
    {
      "day": "2026-07-17",
      "product_count": 100,
      "avg_price": "24.85",
      "min_price": "9.00",
      "trust_score": 78,
      "rules_version": "v0.8"
    }
  ],
  "partner_program": { "active": false },
  "data_updated": "2026-07-18T04:12:09.000Z"
}

GET/badge/{slug}

Embeddable SVG trust badge (200×52): "TRUST 78/100" with a score bar, or "ON RECORD" while the score is pending. Cached 24 h; 404 for stores not on record.

response
image/svg+xml — drop it into an <img> tag. Stores embed it on their own site; every badge links back to the live profile, so the number can't go stale or be faked.

embed example

<a href="https://storeprofiles.com/store/example-beauty">
  <img src="https://storeprofiles.com/badge/example-beauty"
       width="200" height="52"
       alt="StoreProfiles trust 78/100" />
</a>

GET/feed.xml

RSS 2.0 feed of registry activity: the 25 most recent audits (one item per audit) plus one synthetic weekly-digest item, so feed readers and monitoring tools catch new audits without polling the JSON API.

item (audit)
title “{store} audited — {score}/100”, link to the profile, stable guid per audit, and a description quoting the audit's first pro and con, each with its source.
item (weekly)
one “This week in the registry — {ISO week}” item with live counts of audits published, stores claimed and partners queued since Monday; links to /weekly.
headers
Content-Type application/rss+xml, hourly cache.

GET/registry.csv

The whole live registry as one CSV download (Content-Disposition: attachment; filename registry-YYYY-MM-DD.csv) — ready for spreadsheets, pandas or BI tools.

columns
slug, name, domain, niche, status, trust_score, products, distinct_products, min_price, currency, claimed, profile_url. One row per live store, ranked by trust score.
min_price / currency
entry price — the cheapest product priced at 2 or above in the store's modal (most common) currency; the currency column is that modal currency. Same rule the niche reports use, so mixed-currency catalogs never distort the number.
escaping
RFC 4180 — names containing commas, quotes or newlines arrive quoted, inner quotes doubled.

shape example (first rows)

slug,name,domain,niche,status,trust_score,products,distinct_products,min_price,currency,claimed,profile_url
example-beauty,"Example Beauty, Co.",examplebeauty.com,beauty-skincare,ingested,78,100,86,9.00,USD,false,https://storeprofiles.com/store/example-beauty

Terms of use, in plain words

  • CORS is open — every endpoint sends Access-Control-Allow-Origin: *, so browser apps can call it directly.
  • Responses are cached for an hour (the badge for 24 h). Data refreshes on the daily ingest, so polling more often than hourly buys nothing.
  • No auth, no keys — and no uptime or rate-limit promises. Be gentle; abusive traffic gets blocked without ceremony.
  • Where the data comes from:the stores' own public product feeds. Every number is checkable at its source — see /how-we-score.
  • Scores are computed, never sold. No store can pay to be listed, scored, or ranked — and the API returns the same numbers the profile pages show.