# Install the badge

URL: https://submitator.com/docs/guides/install-the-badge

> Some directories list a product only while their badge is on its site. Get the install kit, forward it to your client, check the install and verify it.

## What you'll build

One block in the footer of your client's site that shows your agency's badge and every directory badge the project needs, under your brand. Once it is verified, the directories that ask for a badge open to the project. The block updates by itself, so your client installs it once.

## Before you start

- **A project.** The badge can go up before or after the launch.
- **Someone who can change the site**: your client's developer, or you. The last section of this page is a note to forward to them.

## 1. See what the badge unlocks

Before the launch, the readiness preview counts the directories that wait for the badge. After it, those listings show `action_required` with `action.code` `install_badge`.

```bash
curl https://api.submitator.com/v1/projects/prj_4QzX1m9Lr2Vb7Nc8Tk3HwP/readiness \
  -H "Authorization: Bearer $SUBMITATOR_API_KEY"
```

unlocks from the response:

```json
[{ "requirement": "badge", "directories": 9, "how": "Install the badge on https://ledgerly.test and verify it." }]
```

## 2. Get the install kit

`GET /projects/{project_id}/badge` returns the feed URLs, 6 ready snippets, a command that checks the install and a message to forward.

```bash
curl https://api.submitator.com/v1/projects/prj_4QzX1m9Lr2Vb7Nc8Tk3HwP/badge \
  -H "Authorization: Bearer $SUBMITATOR_API_KEY"
```

```js
const res = await fetch("https://api.submitator.com/v1/projects/prj_4QzX1m9Lr2Vb7Nc8Tk3HwP/badge", {
  headers: { Authorization: `Bearer ${process.env.SUBMITATOR_API_KEY}` },
});
console.log(await res.json());
```

```python
import os
import requests

res = requests.get(
    "https://api.submitator.com/v1/projects/prj_4QzX1m9Lr2Vb7Nc8Tk3HwP/badge",
    headers={"Authorization": f"Bearer {os.environ['SUBMITATOR_API_KEY']}"},
)
print(res.json())
```

Response 200 (recipes cut to 1):

```json
{
  "object": "badge",
  "project": "prj_4QzX1m9Lr2Vb7Nc8Tk3HwP",
  "status": "not_checked",
  "checked_at": null,
  "feed": {
    "json_url": "https://feed.example.net/badge/91bb683b-04df-68e5-fea1-c01f13987d91.json",
    "html_url": "https://feed.example.net/badge/91bb683b-04df-68e5-fea1-c01f13987d91.html"
  },
  "recipes": [
    {
      "platform": "html",
      "title": "Static site",
      "language": "shell",
      "code": "curl -fsS https://feed.example.net/badge/91bb683b-04df-68e5-fea1-c01f13987d91.html -o partials/directory-badges.html"
    }
  ],
  "check_command": "curl -sL https://ledgerly.test | grep -c 'ref=91bb683b-04df-68e5-fea1-c01f13987d91'",
  "client_message": "Please add the directory badges block to the footer of https://ledgerly.test. Some directories list Ledgerly only while their badge shows on the site, and the block keeps those badges up to date by itself. Your developer can pick a ready snippet for Next.js, PHP, WordPress, nginx or a static site."
}
```

The recipes cover `nextjs`, `php`, `wordpress`, `nginx_ssi`, `html` for a static site, and `ai_prompt`, a prompt for an AI coding tool. Each has a `title` for a tab and the project's feed URL already in its `code`.

## 3. Forward it to your client

Send `client_message` as it is, with the recipe for your client's site and the note at the end of this page. The message names the product and nobody else, so it reads as yours.

In test mode the feed URLs have the right shape but return 404, so a recipe renders nothing there.

## 4. Check the install

Once the block is up, `check_command` prints how many badge links the site's home page shows, following redirects as our check does.

```bash
curl -sL https://ledgerly.test | grep -c 'ref=91bb683b-04df-68e5-fea1-c01f13987d91'
```

`0` means the badges are not in the HTML the site serves. The usual cause is a block loaded in the browser with JavaScript, which the check does not run.

## 5. Verify it

`POST /projects/{project_id}/badge/verify` reads the site now and looks for the badge. You can verify a project 10 times per hour.

```bash
curl -X POST https://api.submitator.com/v1/projects/prj_4QzX1m9Lr2Vb7Nc8Tk3HwP/badge/verify \
  -H "Authorization: Bearer $SUBMITATOR_API_KEY"
```

```js
const res = await fetch(
  "https://api.submitator.com/v1/projects/prj_4QzX1m9Lr2Vb7Nc8Tk3HwP/badge/verify",
  { method: "POST", headers: { Authorization: `Bearer ${process.env.SUBMITATOR_API_KEY}` } },
);
console.log(res.status, await res.json());
```

```python
import os
import requests

res = requests.post(
    "https://api.submitator.com/v1/projects/prj_4QzX1m9Lr2Vb7Nc8Tk3HwP/badge/verify",
    headers={"Authorization": f"Bearer {os.environ['SUBMITATOR_API_KEY']}"},
)
print(res.status_code, res.json())
```

Response 200 (some fields left out):

```json
{
  "object": "badge",
  "project": "prj_4QzX1m9Lr2Vb7Nc8Tk3HwP",
  "status": "installed",
  "checked_at": "2026-10-04T09:58:03Z"
}
```

A badge that is not on the site returns 422 `badge_not_found`: run `check_command`, fix the install and verify again.

## 6. What happens next

Once the badge is verified, the directories that need it open to the project. With `auto_replace` on, they are added from the free allowance by themselves, and the listings that waited in `action_required` move on. With it off, add them with `POST /projects/{project_id}/listings`.

Keep the block on the site. Directories that list a product only while their badge shows can take the listing down when it goes.

## Check it worked

- `GET /projects/prj_4QzX1m9Lr2Vb7Nc8Tk3HwP/badge` shows `status` `installed`.
- The readiness preview no longer lists `badge` in `unlocks`.
- Listings with `action.code` `install_badge` move to `in_progress`, and their `listing.in_progress` events arrive.

## What can go wrong

| Code | Status | Fix |
| --- | --- | --- |
| [`badge_not_found`](https://submitator.com/docs/errors#badge_not_found) | 422 | The site does not show the badge. Run `check_command`, fix the install, verify again. In test mode, a host that starts with `nobadge.` never passes. |
| [`rate_limited`](https://submitator.com/docs/errors#rate_limited) | 429 | More than 10 checks this hour for the project. Wait the seconds in `Retry-After`. |
| [`not_found`](https://submitator.com/docs/errors#not_found) | 404 | The project id belongs to the other mode, or to no project. |

## A note for your client's developer

Forward this section as it is.

The badge block holds small badges, each an image link. Some directories keep a listing only while their badge shows on the site, and the block keeps the set current by itself: new badges appear without a change on your side.

- **Put it in the footer of every page**, or at least of the home page.
- **Render it on the server.** The badges must be in the HTML your server sends: a block loaded with client-side JavaScript is not seen. Every snippet does it this way.
- **Never let it break the page.** Fetch the feed with a timeout of 3 seconds or less, and render nothing on an error or any status other than 200. The snippets do both.
- **Keep the links as the feed sends them.** Each badge links to its directory, and the `ref=` in the links is how the install is checked.
- **Cache it if you like.** A response can be cached for 60 seconds; the Next.js snippet refreshes every 5 minutes.

To check the install, run the `check_command` you were sent: any number above `0` means the badges are live on the page.

## Next steps

- [Reach more directories](https://submitator.com/docs/guides/reach-more-directories): the other unlocks.
- [Launch and track](https://submitator.com/docs/guides/launch-and-track): follow the listings the badge opens.
- [Badge](https://submitator.com/docs/api/badge): the install kit and its fields in full.
