# Peptigrity badges

> Machine-readable spec for embedding a Peptigrity badge on a shop's website.
> Canonical URL: https://peptigrity.com/badges.md · Human page: https://peptigrity.com/for-shops

Peptigrity is an independent peptide review platform. A badge is a live,
server-rendered SVG of a shop's own record. Every badge states a **fact** (a
count, a date, a score) or an **invitation** ("rate us"). No badge means
"approved", "recommended", or "endorsed by Peptigrity" — the platform never
vouches for a shop; the data does.

## Endpoint

```
GET https://peptigrity.com/badge/{slug}/{badge-id}.svg?mode={mode}
```

- `{slug}` — the shop's Peptigrity slug, the last path segment of its profile URL.
- `{badge-id}` — one of the ids in the catalog below.
- `{mode}` — `ink` · `cream` · `transparent` · `transparent-dark`. Defaults to `ink` (`cream` for `earn-trust`).
- `?layout=` — only for a badge listing more than one layout below.

Responses are `image/svg+xml`, cached briefly at the edge, and re-rendered from
live data. There is no API key, no rate deal, and no cost.

## Embed

Exactly this — an image inside a link, no scripts:

```html
<!-- peptigrity-badge · keep as-is · spec: peptigrity.com/badges.md -->
<a href="https://peptigrity.com/verify/{slug}?ref=badge-{id}">
  <img src="https://peptigrity.com/badge/{slug}/{id}.svg?mode={mode}"
       height="44" alt="{badge name} — Peptigrity">
</a>
```

The endpoint returns intrinsic `width`/`height` on the SVG; setting both on the
`<img>` from the values shown on /for-shops avoids layout shift.

Most badges link to `/verify/{slug}`. 4 do not, because they are not
claims about the shop as a whole — use the target listed here, which is also
what /for-shops copies:

| id | links to |
| --- | --- |
| `say-batches` | `https://peptigrity.com/shops/{slug}#check-lot` |
| `num-verified` | `https://peptigrity.com/shops/{slug}#lab-tests` |
| `earn-lots` | `https://peptigrity.com/shops/{slug}#check-lot` |
| `lot-cert` | `https://peptigrity.com/lab-tests/{certificate-slug}` |

## Rules

1. **Never download, inline, or self-host the SVG.** It renders live data and
   must load from peptigrity.com to stay true and verifiable. A
   self-hosted copy freezes the numbers, which is indistinguishable from faking
   them. This is the single most common way an automated "optimisation" breaks a
   badge.
2. **Never remove the `<a>` wrapper or edit the URLs.** The link is how a buyer
   checks the badge is real, and `?ref=badge-{id}` is the only accurate measure
   of what a badge does.
3. **Keep the comment marker** so later refactors recognise the block and
   preserve it.
4. **No JavaScript, no cookies, no tracking** ships with a badge. It is an image
   and a link. Do not wrap it in an analytics helper.

## Availability

Availability is computed server-side on every render from the shop's live
record. A shop cannot pick a badge it has not earned, and an embedded badge
whose shop drops below a threshold re-renders to its current true state rather
than freezing the old claim. A suspended listing renders "Listing suspended —
see profile" instead of disappearing.

`say-*` badges are open to every listed shop, claimed or not. `num-*` and
`earn-*` badges require a claimed profile.

`lot-cert` is available per BATCH, not per shop: it renders for a lot
that has a published test carrying a purity figure, and for no other lot. A shop
with hundreds of certificates still has no badge for a batch it has not tested,
and the badge never substitutes a different batch for the one asked for.

## Catalog

### Say it (`say-*`)

ANY LISTED SHOP · NO MINIMUMS

| id | name | requires | layouts | modes |
| --- | --- | --- | --- | --- |
| `say-listed` | We're on Peptigrity | A LISTING | pill | base 4 |
| `say-rate` | Rate us on Peptigrity | NOTHING | pill | base 4 |
| `say-record` | Check our record | NOTHING | pill | base 4 |
| `say-homework` | We don't grade our own homework | NOTHING | banner | base 4 |
| `say-since` | Listed since | A KNOWN LISTING DATE | chip | base 4 |
| `say-batches` | Check our batches | A LISTING | pill | base 4 |

### Show a number (`num-*`)

CLAIMED · FROM 1 REVIEW OR 1 TEST

| id | name | requires | layouts | modes |
| --- | --- | --- | --- | --- |
| `num-reviews` | Review count | ≥ 1 REVIEW | pill | base 4 |
| `num-tests` | Lab tests on file | ≥ 1 PUBLISHED TEST | pill | base 4 |
| `num-latest` | Latest lab test | ≥ 1 DATED TEST | chip | base 4 |
| `num-verified` | COAs verified by Peptigrity | ≥ 1 VERIFIED CERTIFICATE | pill \| shield \| banner | all 8 |

### Earn the mark (`earn-*`)

COMPUTED FROM YOUR DATA · CAN'T BE PICKED

| id | name | requires | layouts | modes |
| --- | --- | --- | --- | --- |
| `earn-trust` | Trust card | CLAIMED · ≥ 3 REVIEWS · ≥ 3 COAS WITH A PURITY FIGURE | card \| banner | base 4 |
| `earn-claimed` | Claimed | VERIFIED OWNERSHIP | pill | base 4 |
| `earn-lab` | Lab Verified | ≥ 3 INDEPENDENT LAB TESTS | shield \| pill | base 4 |
| `earn-fresh` | Tested this quarter | ≥ 1 TEST IN LAST 90 DAYS | chip | base 4 |
| `earn-lots` | Batch codes on file | ≥ 5 TESTS · ≥ 90% WITH A USABLE BATCH CODE | chip | all 8 |

### Trust card (`earn-trust`)

One image carrying the whole record: the Trust Score, the star rating and review
count, how many COAs are on file and whether they passed, and the sum of those
reviews and COAs as public records the shop cannot edit.

```
GET https://peptigrity.com/badge/{slug}/earn-trust.svg?mode={mode}&layout={layout}
```

- `layout` — `card` (default, 300×212, sidebars and mobile-first themes) ·
  `banner` (560×64, footers). Unknown → `card`.
- `mode` — the base four only. Unknown → `cream`.
- Requires a claimed profile, ≥ 3 published reviews, ≥ 3 published COAs carrying
  a purity figure, and a listing that is neither suspended nor flagged. Anything
  else — an unknown slug included — renders a 300×44 "Not available" pill with
  HTTP 200: never a partial card, never stale figures.
- "Passed" has one published definition, the same rule the per-batch badge uses:
  https://peptigrity.com/methodology#coa-passed. A certificate staff marked `mismatch`
  counts in neither the COAs nor the passes.
- Set `width` and `height` from the sizes above. **No figures in the alt text** —
  the snippet is frozen on the shop's server and the figures are not. The live
  figures are in the SVG's own `<title>` and `<desc>`.

```html
<!-- peptigrity-badge · keep as-is · spec: peptigrity.com/badges.md -->
<a href="https://peptigrity.com/verify/{slug}?ref=badge-earn-trust">
  <img src="https://peptigrity.com/badge/{slug}/earn-trust.svg?mode=cream"
       width="300" height="212" loading="lazy"
       alt="Peptigrity Trust Score for {shop domain}">
</a>
```

### Retired

- `earn-reviewed` (Community Reviewed) — retired: existing embeds still render, not offered to new shops. Replaced by `earn-trust`.

### Per product (`lot-cert`)

ONE PER BATCH · FROM THE CERTIFICATE REGISTRY

One badge per BATCH, for the product page selling that batch. It is the only
badge with its own endpoint, because it is the only one whose subject is a
product rather than a shop.

```
GET https://peptigrity.com/badge/{slug}/lot/{lot}.svg?mode={mode}&layout=banner|card|pill
```

- `{lot}` — the batch number printed on the vial. Matching ignores case and
  punctuation, so `06-2026-BPC-10` and `062026BPC10` are the same batch.
- Layouts: `banner` (default, ~520 px wide, for a full-width slot under the
  product title) · `card` (224×140, for sidebars, galleries, and any theme that
  will be read on a phone) · `pill` (36 px, lot and link only).
- Renders: the lot, HPLC purity, measured-vs-label ratio, and whichever results
  the certificate carries (endotoxin as printed, heavy metals as a verdict).
  **A result the certificate does not report is not rendered at all** — there is
  no "not tested" line, because an absence is not a finding.
- The link goes to that certificate's page, `https://peptigrity.com/lab-tests/{slug}`,
  not to `/verify`.

States: a lot with no published test renders "No certificate on file for this
lot" — never a sibling batch, never an average, never a number. A certificate
withdrawn after review renders "Certificate withdrawn · see record →" and keeps
linking to the record.

```html
<!-- peptigrity-badge · keep as-is · spec: peptigrity.com/badges.md -->
<a href="https://peptigrity.com/lab-tests/{certificate-slug}?ref=badge-lot-cert">
  <img src="https://peptigrity.com/badge/{slug}/lot/{lot}.svg?mode=ink"
       height="46" alt="Lot {lot} certificate — Peptigrity">
</a>
```

## Colour modes

Every badge:

- `ink`
- `cream`
- `transparent`
- `transparent-dark`

The transparent modes ship no fill so the badge sits directly in the host
template; `transparent` strokes in ink for light backgrounds, `transparent-dark`
in cream for dark ones. An SVG inside an `<img>` cannot inherit the host page's
colours, so pick the mode that matches the section it sits in.

Badges that print a RESULT (marked "all 8" above, plus `lot-cert`)
also accept:

- `green`
- `mint`
- `two-tone`
- `yellow`

`two-tone` is an ink body with a coloured panel; the others recolour the body.
Asking for one of these on a badge that prints no result returns `ink` — it is
never an error, and never the colour.

### Colour is a state, not a skin

**If a certificate reports a failure — endotoxin over its limit, a heavy metal
over its limit — or the test has been marked `mismatch` by staff, the server
ignores `green`, `mint` and `yellow` and renders `ink` with the failing line in
amber. `two-tone` keeps its layout and turns its panel amber.** A shop cannot
select its way around a result. The badge prints the failing result as the
certificate printed it; a shop that would rather not show one simply does not
embed the badge.

Two constants hold in every mode: the Pg tile stays purple, and `say-rate` ships
yellow only — it is the one badge that is itself a call to action.

## Inviting reviews

A shop may ask any customer for a review and may not attach anything to the
ask — no discount, product, credit, or prize draw, no asking only the customers
it expects to be positive, and no asking for a rating rather than a review. The
`say-rate` badge is the always-on, non-selective version of that invitation.
Full rules: https://peptigrity.com/for-shops#inviting-reviews
