# List public starter preview niches

The curated niches the public starter preview covers, without an API key.

## Endpoint: GET /v1/public/starter-boards

- Method: `GET`
- Path: `/v1/public/starter-boards`
- Authentication: None required. Optional: a Bearer API credential or OAuth access token, which makes the call a metered credentialed call.
- Required scope: `context:read`
- MCP tool: `starter_boards`
- MCP action: `public_niches`

## Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |

## Known errors

- 400 invalid_request for a malformed niche key or an app-<numericStoreId> key; seeded app previews need the authenticated GET /v1/starter-boards/{nicheKey}.
- 401 authentication_required for an invalid credential; a credential that fails is never treated as anonymous.
- 403 authorization_required for an MCP credential without context:read.
- 404 not_found for a niche key outside the curated starter boards.
- 429 rate_limited with window (minute or day) and retryAfterSeconds for an anonymous caller, or the credential’s per-minute read limit; honor Retry-After.
- 429 daily_call_limit; the plan's daily API and MCP calls are used until 00:00 UTC.
- 503 public_preview_unavailable while the public starter preview is switched off; retry later.
- 503 timeout when the stored read ran out of its time budget; retry after Retry-After.

## Request

No query or body, and no credential needed. The list is bounded to the curated catalogue.

```
curl --get 'https://api.peekpanda.com/v1/public/starter-boards'
```

## MCP request

Call starter_boards with action public_niches. Path fields go in params, filters in query, and a write body in body.

```
{
  "name": "starter_boards",
  "arguments": {
    "request": {
      "action": "public_niches"
    }
  }
}

```

## Response

Up to 20 niches, each with a stable key, a label and up to six iOS apps named by store ID, name, icon and category. Apps the catalogue does not hold are left out.

```
{
  "data": [
    {
      "key": "calorie-tracking",
      "label": "Calorie tracking",
      "apps": [
        {
          "storeId": "0000000000",
          "name": "Example Calories",
          "iconUrl": null,
          "category": null
        }
      ]
    }
  ]
}

```

## Source

The curated PeekPanda starter-board niches and stored public competitor evidence: the app paid ad membership, the paid ad library’s last sighting of each ad, stored keyword rankings and the Viral Library. No private customer content is returned.

## Refresh

Reads stored observations only and never starts provider collection. A niche is read again at most every five minutes; thumbnail links are signed for each response and stay valid for 15 to 30 minutes.

## Access, limits and caching

Without an Authorization header the call is anonymous and free, counted in shared storage only (a 503 public_preview_unavailable answers when it cannot be counted): each client network (an IPv4 address or an IPv6 /64) may send 20 requests a minute and 200 a UTC day, and all anonymous callers together share 1,200 a minute. A 429 says which window was used up (`window`: `minute` or `day`) and when to retry (`retryAfterSeconds` and `Retry-After`); `X-RateLimit-Limit`, `X-RateLimit-Remaining` and `X-RateLimit-Reset` describe the current window. With an Authorization header the call is credentialed: it needs context:read, counts toward the plan holder’s shared daily allowance (Peek 30, Panda 1,000, reset 00:00 UTC) and the per-minute read limit, and an invalid credential is refused rather than treated as anonymous. Responses are `Cache-Control: private, max-age=60`, vary by Authorization and are marked `X-Robots-Tag: noindex`.
